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
*** 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 @@ Information here is mostly Android & Linux-specific and may not be 100% accurate
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.
### 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!
* 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).
* 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 @@ smart about them.
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,
......
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