Examples of things that require relative relocations:
// Pointer to yourself. extern const void* const kUserDataKey = &kUserDataKey; // Array of pointers. extern const char* const kMemoryDumpAllowedArgs[] = {"dumps", nullptr}; // Array of structs that contain one or more pointers. extern const StringPiece kStrings[] = {"one, "two"};
Vtables are arrays of function pointers, and so require relative relocations. However, on some Chrome platforms we use a non-standard ABI that uses offsets rather than pointers in order to remove the relocations overhead (crbug/589384).
.rel.dyn
, .rel.plt
, .rela.dyn
, or .rela.plt
.REL
, RELA
, APS2
, or RELR
.REL
is default for arm32. It uses two words to per relocation: address
, flags
.RELA
is default for arm64. It uses three words per relocation: address
, flags
, addend
.APS2
is what Chrome for Android uses. It stores the same fields as REL/
RELA`, but uses variable length ints (LEB128) and run-length encoding.RELR
is what Chrome OS uses, and is supported in Android P+ (tracking bug for enabling). It encodes only relative relocations and uses a bitmask to do so (which works well since all symbols that require relocations live in .data.rel.ro
)..reloc
section..reloc
section has a small overhead as well..rela.dyn
section of more than 14MiB!APS2
] to compress these down to ~300kb.RELR
] would require only 60kb, but is not yet enabled..relocs
sections that sum to 620KiB..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).mremap
onto shared memory to dedupe after-the-fact.# 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
It's not practical to avoid them altogether, but there are times when you can be smart about them.
For Example:
// 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"}; // The following requires no string padding, but uses 4 relocatable pointers. // Total size overhead: // 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"};
Notes:
Here's a simpler example:
// No pointer, no relocation. Just 5 bytes of character data. extern const char kText[] = "asdf"; // Requires pointer, relocation, and character data. // In most cases there is no advantage to pointers for strings. // When not "extern", the compiler can often figure out how to avoid the relocation. extern const char* const kText = "asdf";
Another thing to look out for: