Commit 0eeb5fd9 authored by Andrew Grieve's avatar Andrew Grieve Committed by Commit Bot

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 <agrieve@chromium.org>
Reviewed-by: default avatarBruce Dawson <brucedawson@chromium.org>
Cr-Commit-Position: refs/heads/master@{#718811}
parent 0afbdeb2
# Native Relocations # Native Relocations
*** note [TOC]
Information here is mostly Android & Linux-specific and may not be 100% accurate.
***
## What are they? ## 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 * They tell the runtime linker a list of addresses to post-process after
loading the executable into memory. loading the executable into memory.
* There are several types of relocations, but >99% of them are "relative" * There are several types of relocations, but >99% of them are "relative"
...@@ -14,45 +10,81 @@ Information here is mostly Android & Linux-specific and may not be 100% accurate ...@@ -14,45 +10,81 @@ Information here is mostly Android & Linux-specific and may not be 100% accurate
initialized with the address of something. initialized with the address of something.
* This includes vtables, function pointers, and string literals, but not * This includes vtables, function pointers, and string literals, but not
`char[]`. `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 ### Linux & Android Relocations (ELF Format)
smaller file size. * Relocations are stored in sections of type: `REL`, `RELA`, [`APS2`][APS2], or
* As of Oct 2019, Chrome on Android has about 390000 of them. [`RELR`][RELR].
* Windows and Mac have them as well, but I don't know how they differ. * 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? ## Why do they matter?
* **Binary Size:** Except on Android, relocations are stored very ### Binary Size
inefficiently. * On Linux, relocations are stored very inefficiently.
* Chrome on Linux has a `.rela.dyn` section of more than 14MiB! * As of Oct 2019:
* Android uses a [custom compression scheme][android_relro1] to shrink them * Chrome on Linux has a `.rela.dyn` section of more than 14MiB!
down to ~300kb. * Chrome on Android uses [`APS2`] to compress these down to ~300kb.
* There is an even better [RELR][RELR] encoding available on Android P+, but * Chrome on Android with [`RELR`] would require only 60kb, but is
not widely available on Linux yet. It makes relocations ~60kb. [not yet enabled][relr_bug].
* **Memory Overhead:** Symbols with relocations cannot be loaded read-only * Chrome on Windows (x64) has `.relocs` sections that sum to 620KiB.
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. [relr_bug]: https://bugs.chromium.org/p/chromium/issues/detail?id=895194
`.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 ### Memory Overhead
after it's relocated, so the linker makes it read-only once relocations are * On Windows, there is [almost no memory overhead] from relocations.
applied (but by that point the damage is done and we have the dirty pages). * 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 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 loading the shared library at the same address in all processes, and then
`mremap` onto shared memory to dedupe after-the-fact. `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 [zygote]: linux_zygote.md
[RELR]: https://reviews.llvm.org/D48247 [relro_sharing]: android_native_libraries.md#relro-sharing
[android_relro1]: android_native_libraries.md#Packed-Relocations
[android_relro2]: 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? ## How do I see them?
```sh ```sh
# For ELF files:
third_party/llvm-build/Release+Asserts/bin/llvm-readelf --relocs out/Release/libmonochrome.so 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? ## Can I avoid them?
...@@ -61,22 +93,36 @@ smart about them. ...@@ -61,22 +93,36 @@ smart about them.
For Example: For Example:
```c++ ```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. // Total size overhead: 4 * 5 = 20 bytes.
const char kArr[][5] = {"as", "ab", "asdf", "fi"}; 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: // Total size overhead:
// 64-bit: 8 bytes per pointer + 24 bytes per relocation + 14 bytes of char = 142 bytes // Linux 64-bit: (8 bytes per pointer + 24 bytes per relocation) * 4 entries + 14 bytes of char = 142 bytes
// 32-bit: 4 bytes per pointer + 8 bytes per relocation + 14 bytes of char = 62 bytes // Windows 64-bit: (8 bytes per pointer + 2 bytes per relocation) * 4 entries + 14 bytes of char = 54 bytes
const char *kArr2[] = {"as", "ab", "asdf", "fi"}; // 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: Notes:
* String literals are de-duped with others in the binary, so it's possible that * String literals (but not char arrays) are de-duped with others in the binary,
the second example above might use 14 fewer bytes. so it is possible that the second example above might use 14 fewer bytes.
* Not all string literals require relocations. Only those that are stored into * Not all string literals require relocations. Which ones require them depends
global variables require them. 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: Another thing to look out for:
* Large data structures with relocations that you don't need random access to, * Large data structures with relocations that you don't need random access to,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment