This is an archive of the discontinued LLVM Phabricator instance.

[ELF] Support --pack-dyn-relocs=rel+relr
AbandonedPublic

Authored by mcgrathr on May 8 2020, 10:49 PM.

Details

Summary

This rewrites RELA to REL as well as generating RELR. This is a
more compact representation for dynamic linker ABIs that support
both REL and RELA encodings (such as Fuchsia's).

Diff Detail

Event Timeline

mcgrathr created this revision.May 8 2020, 10:49 PM

I'm not sure what all tests this should have. It was surprisingly easy to implement and seems to work perfectly. I've done a Fuchsia build with it that shows binaries that look as they should by eyeball, though I haven't yet tested it at runtime.

Oh, and perhaps I'll update that comment since we do know why ELF specified RELA in the first place, which is for general-case reloc types for machines not like x86, where some reloc types don't apply to locations that store as many bits as the full address size that the addend can be in the general case. When you have TEXTRELs, then any dynamic reloc can also be such a type. For newer ABIs that never allowed TEXTRELs, I think people just assumed that the encoding for dynamic relocs should match the encoding for ET_REL relocs without thinking about it deeply. In the ABIs we're concerned with today, the only narrow reloc type that might appear as a dynamic reloc is ABS32 in ELFCLASS64, but limiting addends to 32 bits is no more limiting than the rules of the small memory model, so you just wouldn't use rela->rel encoding with large memory model (or you could punt only for specific programs when you hit an out of range addend for real, which seems unlikely). (A similar constraint has always been tolerated for R_ARM_MOV[WT]* relocs where EM_ARM is canonically REL rather than RELA and so addends used in relocs for movw/movt instructions are limited to 16 bits though the address computation is always a full 32 bit computation before the reloc stores the high or low 16 bits.)

Also note that compatible dynamic linkers support not just either, but both in the same executable (though the format requires that only one or the other be the format for PLT relocs, but those never need addends anyway). So for the large model case one could theoretically produce RELA for any relocs whose addend is too large for the bits available in the relocated entity while still producing REL for everything that fits. (The need ever to support large addends in the real world seems unlikely, but just saying.)

MaskRay added a comment.EditedMay 9 2020, 11:01 AM

I haven't thought much on this yet. First impression: why isn't the RELA->REL toggle a new option? It does not seem to fit with the rest of --pack-dyn-relocs which selects Android packed dynamic relocations or RELR or both.

Regarding tests, you can add llvm-readelf -S RUN lines to check .rel.dyn or .rela.dyn. See some newly touched test files.

musl ld.so supports both REL and RELA. I can probably finish the patch and test it on musl.

I haven't thought much on this yet. First impression: why isn't the RELA->REL toggle a new option? It does not seem to fit with the rest of --pack-dyn-relocs which selects Android packed dynamic relocations or RELR or both.

--pack-dyn-relocs seems exactly appropriate to me since it's about packing the dynamic relocs. It does RELA->REL conversion just as the existing option does REL(A)->RELR conversion. But I'm not concerned with the switch syntax. I'm fine with whatever syntax people prefer. (For example, I don't at all think it's important to disallow the RELA->REL conversion without RELR support, I just don't care about that mode at all.) I probably wouldn't have added --pack-dyn-relocs with its string syntax in the first place, but instead just added separate -z android-relocs and -z relr switches so the new one would be -z rel or something. But given --pack-dyn-relocs exists, it seems like the natural place for this to me now.

Regarding tests, you can add llvm-readelf -S RUN lines to check .rel.dyn or .rela.dyn. See some newly touched test files.

musl ld.so supports both REL and RELA. I can probably finish the patch and test it on musl.

Thanks very much! Fuchsia's current dynamic linker is a (distant) fork from musl and supports both as well. I haven't looked at musl lately so perhaps it hasn't added RELR support as Fuchsia did (where RELR encoding is the preferred default). So using and testing with musl (or older musl) might be a good reason to support doing RELA->REL encoding without doing RELR encoding.

I haven't thought much on this yet. First impression: why isn't the RELA->REL toggle a new option? It does not seem to fit with the rest of --pack-dyn-relocs which selects Android packed dynamic relocations or RELR or both.

--pack-dyn-relocs seems exactly appropriate to me since it's about packing the dynamic relocs. It does RELA->REL conversion just as the existing option does REL(A)->RELR conversion. But I'm not concerned with the switch syntax. I'm fine with whatever syntax people prefer. (For example, I don't at all think it's important to disallow the RELA->REL conversion without RELR support, I just don't care about that mode at all.) I probably wouldn't have added --pack-dyn-relocs with its string syntax in the first place, but instead just added separate -z android-relocs and -z relr switches so the new one would be -z rel or something. But given --pack-dyn-relocs exists, it seems like the natural place for this to me now.

I am inclined to agree. I've added a few suggestions about the code.

lld/ELF/Driver.cpp
743

aside: I wonder why we support "android+relr", but not "android,relr". The latter form looks more natural to me.

755

Its a bit hard to read a tuple of 3 bools probably? Perhaps I'd do the same what we do for -hash-style.
(See "Parse -hash-style={sysv,gnu,both}.") below.

I.e. I'd:

  1. Inline this method.
  2. Set config->androidPackDynRelocs, config->relrPackDynRelocs, config->relPackDynRelocs to false by default.

And do something similar to what -hash-style does:

// Parse -hash-style={sysv,gnu,both}.
if (auto *arg = args.getLastArg(OPT_pack_dyn_relocs)) {
  StringRef s = arg->getValue();
  if (s.startsWith("android")) {
    config->androidPackDynRelocs = true;
    // Check "+relr" ..
  } else if ...
  ....
}
1222

This comment have double spaces after full stops.

1235

I believe usually we assign config variables once. So it could be:

config->isRela = !config->relPackDynRelocs && ...
arichardson added inline comments.May 12 2020, 5:49 AM
lld/ELF/Driver.cpp
743

I agree. How about allowing comma-separated list where the order does not matter?

746

I don't think it makes sense to omit an option because it might be a typo.
I doubt many people will manually pass -Wl,--pack-dyn-relocs=, it will probably come from some build system default.
Those who pass it manually probably know to check the output binary to see if worked as expected.

I would quite like to see the plain rel option since it's useful on platforms that don't have RELR and also useful for LLD tests to check that we always write addends in REL format.
I noticed quite a few bugs in the RELA->REL conversion in the past (I have been working mostly with MIPS where clang emits RELA, but LLD converts them to REL). Having this conversion would allow writing tests that don't depend on MIPS.

grimar added inline comments.May 12 2020, 5:54 AM
lld/ELF/Driver.cpp
743

It would look better to me.

MaskRay added a comment.EditedMay 12 2020, 8:37 AM

I probably wouldn't have added --pack-dyn-relocs with its string syntax in the first place, but instead just added separate -z android-relocs and -z relr switches so the new one would be -z rel or something. But given --pack-dyn-relocs exists, it seems like the natural place for this to me now.

I learned that -z is reserved for ELF specific options in GNU ld. So, -z would indeed be more suitable. -z rel may be a good name. Are you going to create a feature request on GNU ld side:) ?

Thanks very much! Fuchsia's current dynamic linker is a (distant) fork from musl and supports both as well. I haven't looked at musl lately so perhaps it hasn't added RELR support as Fuchsia did (where RELR encoding is the preferred default). So using and testing with musl (or older musl) might be a good reason to support doing RELA->REL encoding without doing RELR encoding.

I even posted a musl patch last year, but it could not be accepted because RELR is not in the standard. (https://groups.google.com/forum/#!topic/generic-abi/9OO5vhxb00Y "Ongoing Maintenance of the gABI" might make the situation better.)

-z rel does not need to be coupled with RELR and it has its own usefulness which can be easily justified. Dynamic relocations usually have 0 addend. GLOB_DAT, J[U]MP_SLOT and COPY always have 0 addend and do not need to read the implicit addend. The symbolic absolute relocation type usually has 0 addend. Unfortunately FreeBSD rtld and glibc ld.so are structured in the way that supporting both REL and RELA is not out-of-the-box.

lld/ELF/Driver.cpp
743

Note, in compiler drivers (GCC+clang), -Wl, does not have escapes for commas, so commas in the linker generally does not work well.

arichardson added inline comments.May 12 2020, 9:59 AM
lld/ELF/Driver.cpp
743

That is a good very good reason not to use ,.
Maybe allowing the option multiple times is the best solution. Or if that is too verbose, + or : as a separator should be fine.
I would also prefer if we didn't require a fixed order: why should rel+relr be accepted but not relr+rel?

If people are agreed, I think separate -z rel, -z relr, and -z android-relocs flags that operate independent makes the most sense. The existing --pack-dyn-relocs can be accepted for compatibility, but need not get any new supported values.

MaskRay added a subscriber: danalbert.EditedMay 24 2020, 1:41 PM

If people are agreed, I think separate -z rel, -z relr, and -z android-relocs flags that operate independent makes the most sense. The existing --pack-dyn-relocs can be accepted for compatibility, but need not get any new supported values.

-z rel and -z relr look good to me. I created D80496 for -z rel and -z rela. (It should work out of the box with --pack-dyn-relocs=android)

I don't know how the magic APS2 was picked but I think the -z option for Android packed relocation section can mention the magic, i.e. -z pack-dyn-relocs=APS2 or similar. @danalbert

On the GNU ld side, I created https://sourceware.org/pipermail/binutils/2020-May/111086.html but there has been no response ¯\_(ツ)_/¯

MaskRay requested changes to this revision.Jul 28 2020, 9:41 AM

Seems that this can be closed because D80496 landed.

This revision now requires changes to proceed.Jul 28 2020, 9:41 AM
mcgrathr abandoned this revision.Jul 28 2020, 10:40 AM

obviated by -z rel