native_relocations.md: Add info about win and cros
Change-Id: I12bcf5d208b4f272bc5e3e538093ebe968e2f538
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1914552
Commit-Queue: Andrew Grieve <[email protected]>
Reviewed-by: Bruce Dawson <[email protected]>
Cr-Commit-Position: refs/heads/master@{#718811}
diff --git a/docs/native_relocations.md b/docs/native_relocations.md
index 0910e6f9..aeb85f9 100644
--- a/docs/native_relocations.md
+++ b/docs/native_relocations.md
@@ -1,12 +1,8 @@
# Native Relocations
-*** note
-Information here is mostly Android & Linux-specific and may not be 100% accurate.
-***
+[TOC]
## What are they?
- * For ELF files, they are sections of type REL, RELA, or RELR. They generally
- have the name ".rel.dyn" and ".rel.plt".
* They tell the runtime linker a list of addresses to post-process after
loading the executable into memory.
* There are several types of relocations, but >99% of them are "relative"
@@ -14,45 +10,81 @@
initialized with the address of something.
* This includes vtables, function pointers, and string literals, but not
`char[]`.
- * Each relocation is stored as either 2 or 3 words, based on the architecture.
- * On Android, they are compressed, which trades off runtime performance for
- smaller file size.
- * As of Oct 2019, Chrome on Android has about 390000 of them.
- * Windows and Mac have them as well, but I don't know how they differ.
+
+### Linux & Android Relocations (ELF Format)
+ * Relocations are stored in sections of type: `REL`, `RELA`, [`APS2`][APS2], or
+ [`RELR`][RELR].
+ * Relocations are stored in sections named: `.rel.dyn`, `.rel.plt`,
+ `.rela.dyn`, or `.rela.plt`.
+ * For `REL` and `RELA`, each relocation is stored using either 2 or 3 words,
+ based on the architecture.
+ * For `RELR` and `APS2`, relative relocations are compressed.
+ * [`APS2`][APS2]: Somewhat involved compression which trades off runtime
+ performance for smaller file size.
+ * [`RELR`][RELR]: Supported in Android P+. Smaller and simpler than `APS2`.
+ * `RELR` is [used by default][cros] on Chrome OS.
+ * As of Oct 2019, Chrome on Android (arm32) has about 390,000 of them.
+
+[APS2]: android_native_libraries.md#Packed-Relocations
+[RELR]: https://reviews.llvm.org/D48247
+[cros]: https://chromium-review.googlesource.com/c/chromiumos/overlays/chromiumos-overlay/+/1210982
+
+### Windows Relocations (PE Format)
+ * For PE files, relocaitons are stored in per-code-page
+ [`.reloc` sections][win_relocs].
+ * Each relocation is stored using 2 bytes. Each `.reloc` section has a small
+ overhead as well.
+ * 64-bit executables have fewer relocations thanks to the ability to use
+ RIP-relative (instruction-relative) addressing.
+
+[win_relocs]: https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#the-reloc-section-image-only
## Why do they matter?
- * **Binary Size:** Except on Android, relocations are stored very
- inefficiently.
- * Chrome on Linux has a `.rela.dyn` section of more than 14MiB!
- * Android uses a [custom compression scheme][android_relro1] to shrink them
- down to ~300kb.
- * There is an even better [RELR][RELR] encoding available on Android P+, but
- not widely available on Linux yet. It makes relocations ~60kb.
- * **Memory Overhead:** Symbols with relocations cannot be loaded read-only
- and result in "dirty" memory. 99% of these symbols live in `.data.rel.ro`,
- which as of Oct 2019 is ~6.5MiB on Linux and ~2MiB on Android.
- `.data.rel.ro` is data that *would* have been put into `.rodata` and mapped
- read-only if not for the required relocations. It does not get written to
- after it's relocated, so the linker makes it read-only once relocations are
- applied (but by that point the damage is done and we have the dirty pages).
+### Binary Size
+ * On Linux, relocations are stored very inefficiently.
+ * As of Oct 2019:
+ * Chrome on Linux has a `.rela.dyn` section of more than 14MiB!
+ * Chrome on Android uses [`APS2`] to compress these down to ~300kb.
+ * Chrome on Android with [`RELR`] would require only 60kb, but is
+ [not yet enabled][relr_bug].
+ * Chrome on Windows (x64) has `.relocs` sections that sum to 620KiB.
+
+[relr_bug]: https://bugs.chromium.org/p/chromium/issues/detail?id=895194
+
+### Memory Overhead
+ * On Windows, there is [almost no memory overhead] from relocations.
+ * On Linux and Android, memory with relocations cannot be loaded read-only and
+ result in dirty memory. 99% of these symbols live in `.data.rel.ro`, which as
+ of Oct 2019 is ~6.5MiB on Linux and ~2MiB on Android. `.data.rel.ro` is data
+ that *would* have been put into `.rodata` and mapped read-only if not for the
+ required relocations. The memory does not get written to after it's
+ relocated, so the linker makes it read-only once relocations are applied (but
+ by that point the damage is done and we have the dirty pages).
* On Linux, we share this overhead between processes via the [zygote].
- * [On Android][android_relro2], we share this overhead between processes by
+ * [On Android][relro_sharing], we share this overhead between processes by
loading the shared library at the same address in all processes, and then
`mremap` onto shared memory to dedupe after-the-fact.
- * **Start-up Time** The runtime linker applies relocations when loading the
- executable. On low-end Android, it can take ~100ms (measured on a first-gen
- Android Go devices with APS2 relocations). On Linux, it's
- [closer to 20ms][zygote].
+[almost no memory overhead]: https://devblogs.microsoft.com/oldnewthing/20160413-00/?p=93301
[zygote]: linux_zygote.md
-[RELR]: https://reviews.llvm.org/D48247
-[android_relro1]: android_native_libraries.md#Packed-Relocations
-[android_relro2]: android_native_libraries.md#relro-sharing
+[relro_sharing]: android_native_libraries.md#relro-sharing
+
+### Start-up Time
+ * On Windows, relocations are applied just-in-time on page faults, and are
+ backed by the PE file (not the pagefile).
+ * On other platforms, the runtime linker applies all relocations upfront.
+ * On low-end Android, it can take ~100ms (measured on a first-gen Android Go
+ devices with APS2 relocations).
+ * On Linux, it's [closer to 20ms][zygote].
## How do I see them?
```sh
+# For ELF files:
third_party/llvm-build/Release+Asserts/bin/llvm-readelf --relocs out/Release/libmonochrome.so
+
+# For PE files:
+python tools\win\pe_summarize.py out\Release\chrome.dll
```
## Can I avoid them?
@@ -61,22 +93,36 @@
For Example:
```c++
-// Wastes 2 bytes for each smaller string but creates no relocations.
+// The following uses 2 bytes of padding for each smaller string but creates no relocations.
// Total size overhead: 4 * 5 = 20 bytes.
const char kArr[][5] = {"as", "ab", "asdf", "fi"};
-// String data stored optimally, but uses 4 relocatable pointers.
+// The following requires no string padding, but uses 4 relocatable pointers.
// Total size overhead:
-// 64-bit: 8 bytes per pointer + 24 bytes per relocation + 14 bytes of char = 142 bytes
-// 32-bit: 4 bytes per pointer + 8 bytes per relocation + 14 bytes of char = 62 bytes
-const char *kArr2[] = {"as", "ab", "asdf", "fi"};
+// Linux 64-bit: (8 bytes per pointer + 24 bytes per relocation) * 4 entries + 14 bytes of char = 142 bytes
+// Windows 64-bit: (8 bytes per pointer + 2 bytes per relocation) * 4 entries + 14 bytes of char = 54 bytes
+// CrOS 64-bit: (8 bytes per pointer + ~0 bytes per relocation) * 4 entries + 14 bytes of char = ~46 bytes
+// Android 32-bit: (4 bytes per pointer + ~0 bytes per relocation) * 4 entries + 14 bytes of char = ~30 bytes
+const char * const kArr2[] = {"as", "ab", "asdf", "fi"};
```
-Note:
-* String literals are de-duped with others in the binary, so it's possible that
- the second example above might use 14 fewer bytes.
-* Not all string literals require relocations. Only those that are stored into
- global variables require them.
+Notes:
+* String literals (but not char arrays) are de-duped with others in the binary,
+ so it is possible that the second example above might use 14 fewer bytes.
+* Not all string literals require relocations. Which ones require them depends
+ on the ABI. Generally, All global variables that are initialized to the
+ address of something require them.
+
+Here's a simpler example:
+
+```c++
+// No pointer, no relocation. Just 5 bytes of character data.
+const char kText[] = "asdf";
+
+// Requires pointer, relocation, and character data.
+// In most cases there is no advantage to pointers for strings.
+const char* const kText = "asdf";
+```
Another thing to look out for:
* Large data structures with relocations that you don't need random access to,