This is an archive of the discontinued LLVM Phabricator instance.

[ELF] - implemented --eh-frame-hdr command line option.
ClosedPublic

Authored by grimar on Dec 22 2015, 4:37 AM.

Details

Summary

--eh-frame-hdr
Request creation of ".eh_frame_hdr" section and ELF "PT_GNU_EH_FRAME" segment header.

Both gold and the GNU linker support an option --eh-frame-hdr which tell them to construct a header for all the .eh_frame sections. This header is placed in a section named .eh_frame_hdr and also in a PT_GNU_EH_FRAME segment. At runtime the unwinder can find all the PT_GNU_EH_FRAME segments by calling dl_iterate_phdr.
This section contains a lookup table for quick binary search of FDEs.
Detailed info can be found here:
http://www.airs.com/blog/archives/462

Diff Detail

Event Timeline

grimar updated this revision to Diff 43439.Dec 22 2015, 4:37 AM
grimar retitled this revision from to [ELF] - implemented --eh-frame-hdr command line option..
grimar updated this object.
grimar added reviewers: ruiu, rafael.
grimar added subscribers: llvm-commits, grimar.
grimar updated this object.Dec 22 2015, 4:42 AM
grimar updated this revision to Diff 43546.Dec 23 2015, 10:04 AM
  • Rebased.
  • Minor formatting/other improvements.
ruiu added inline comments.Dec 24 2015, 9:39 PM
ELF/OutputSections.cpp
875

Please add a short comment with the URL to the Ian's blog article.

879

Is this value correct? (If correct, it needs a comment.)

882

This function needs a brief comment.

891–899

I'd make this a function so that you write

case ...:
  return read16<E>(F.PCRel);

instead of

case ...:
  PcRel = read16<E>(F.PCRel);
  break;
937

Why don't you use range-based for loop?

968

Ah, OK, so sh_size is initialized to 12 and change in size as you add new FDEs. You want to write about that as a comment.

1153

Add a comment.

// Read a byte and advance D by one byte.

I think you don't need to template this function.

1193

Isn't this a fatal error?

1254

You can remove template <class ELFT>. Please move this just below readByte.

ELF/OutputSections.h
448

Alive -> Live.

test/ELF/eh-frame-hdr-no-out.s
3

How did you create the binary file? Can you use an assembler to create that file?

grimar updated this revision to Diff 43624.Dec 25 2015, 3:07 AM

Review comments addressed.

ELF/OutputSections.cpp
875

Done.

879

Added comment.

882

Done.

937

Interesting question. Fixed.

968

Added comment.

1153

Done.

1193

Thats a question. I think it is not. Linker here just should merge the .eh_frame sections in the way it can. It does not need to support any new versions for example to do that. But .eh_frame_hdr can`t be generated then without knowing internals.
Since my patch is about generating eh_frame_hdr then its correct for it to be Live=false with warning I think.

1254

Ah, yes, initially I did it as class member and forgot to remove after making static.
Fixed.

test/ELF/eh-frame-hdr-no-out.s
3

I dont know any way to generate corrupted CIE or CIE with specified version using assembler.
That is done by compiler itself I believe.
So I just took sample and then used hex editor to manually change the version.

grimar updated this revision to Diff 43625.Dec 25 2015, 3:12 AM

Fixed urls formatting.

ruiu added inline comments.Jan 8 2016, 2:55 PM
ELF/OutputSections.cpp
767

Add a space before "--".

778–779

Remove "llvm::ELF::".

780

` -> '

781

Its -> It's

794

Can you remove "typename EhFrameHdr<ELFT>::"?

800

switch (F.enc & 0xF)

831

It is better to advance Buf here.

Buf += 12;
851

Isn't parameter Sec be non-null? If it is, you can just do

if (this->Sec != Sec)
1122–1124

We can exit from this function as soon as we read data, no?

return readByte(D, &Cie.FdeEncoding));
1136

Ditto

ELF/OutputSections.h
436

Please add a comment to this class.

437

You can remove this typedef.

grimar updated this revision to Diff 44511.Jan 11 2016, 7:57 AM
grimar marked 9 inline comments as done.
  • Addressed review comments.
  • Rebased.
ELF/OutputSections.cpp
767

Done, comment was moved to class EhFrameHdr definition.

780

Removed that line.

851

Point to do "if (this->Sec)" check here is to avoid warning and disabling of header for first assignEhFrame call. I only want to warn if one ehframe is assigned already and somebody tries to assign another one.

1122–1124

I am not sure it is better. At first look it`s like a little optimization of parsing augmentation string but in fact it can hide a potential error when CIE information is corrupted. Early exit can hide warning about that if 'R' is not the latest in a sequence.

1136

Hmm, I dont think its "Ditto", the propose of the function is to read 1 byte that represents the pointer encoding for the address pointers used in the FDE, which is read in 'R', so we need to read and skip everything we met at least until we read 'R'.

ruiu added inline comments.Jan 11 2016, 10:38 AM
ELF/OutputSections.cpp
879

` -> '

892

Remove this empty line.

959

So, if Sec is nonnull but this->Sec can be null,

  • If this->Sec == nullptr, (this->Sec != Sec) can never be true (because Sec is not null), no warning is displayed.
  • If this->Sec != nullptr, (this->Sec != Sec) is true only when somebody tries to assign another one.

But this is a minor point. Leave it as is if you think yours more readable.

1122–1124

I'm pretty sure that that is better if this code is just for checking consistency. We generally don't want to read any data unless it is absolutely necessary to link stuff. It is compiler's responsibility to feed consistent file to the linker, so the linker doesn't have to verify all bits. Doing less is important for performance.

grimar updated this revision to Diff 44614.Jan 12 2016, 2:26 AM
grimar marked 2 inline comments as done.
  • Addressed review comments.
ELF/OutputSections.cpp
879

Sorry, I dont get what you want me to do here ?

959
if (this->Sec != Sec) {
 warning("multiple .eh_frame sections not supported for .eh_frame_hdr");
...

So initially (this->Sec != Sec) is always true, because this->Sec is null and Sec is not. Them are always not equal at first run. Warning is displayed, but it should not.

1122–1124

Ok, done.

ruiu added inline comments.Jan 12 2016, 5:37 AM
ELF/OutputSections.cpp
879

I meant please use apostrophe (') instead of backquote (`) for contractions.

1085

This function reads only encoding, right? Then maybe we should change this function signature to

ErrorOr<uint8_t> getFdeEncoding(ArrayRef<uint8_t> D)

?

Also I'm wondering if corrupted CIEs/FDEs are so prevalent that we have to take care of them. For now, I'd like to simply use error() whenever we find something wrong. Then we can change the signature to

uint8_t getFdeEncoding(ArrayRef<uint8_t> D)

which is pretty simple to understand.

grimar updated this revision to Diff 44645.Jan 12 2016, 9:30 AM
grimar marked 2 inline comments as done.

Addressed review comments (refactored getFdeEnc method).

ELF/OutputSections.cpp
1085

What about getFdeEnc() then ? (to calm down the clang format).
I also changed readByte and skipLeb128 to uint8_t readByte() and void skipLeb128().
And introduced cieParseError() more method to report CIE parse errors in a single place.

grimar added inline comments.Jan 12 2016, 9:32 AM
ELF/OutputSections.cpp
1085

Please ignore getFdeEnc part. getFdeEncoding() is fine now, I`ll update patch in a minute.

grimar updated this revision to Diff 44647.Jan 12 2016, 9:33 AM

getFdeEnc() -> getFdeEncoding()

ruiu added inline comments.Jan 12 2016, 11:04 AM
ELF/OutputSections.cpp
959

You can remove {}.

1020–1025

Please use Type and Flags instead of sh_type and sh_flags because of the LLVM coding style.

1043–1045

Do we need this? If this function is called only at a few places, I'd just inline it.

1071

This should be error() instead of llvm_reachable() because it is logically reachable if an input is corrupted.

1098

This is probably better.

if (Version != 1 && Version != 3)
  error("FDE version 1 or 3 expected, but got " + Version);
1106
if (readByte(D) != 1)
  error(".eh_frame alignment must be 1")
1112–1117

At this point it is guaranteed that Version is either 1 or 3, so

if (Version == 1)
  readByte(D);
else
  skipLeb128(D);
1129

More specific error message would be appreciated.

1142

More specific error message would be good. (error("Unknown XXX") or something like that.)

ELF/OutputSections.h
286

Is unsigned the right type here? If the linker runs on a 32-bit computer, it is 32-bit, but can it link a large 64-bit program?

442

Replace ` with ' (in general for propositions.)

grimar updated this revision to Diff 44718.Jan 13 2016, 1:51 AM
grimar marked 9 inline comments as done.
  • Addressed review comments
  • Fixed eh-frame-hdr-no-out.s test
ELF/OutputSections.cpp
1020–1025

Hmm not sure how that happend. Fixed.

1043–1045

Now when there are few more specific errors introduced there is probably no need in that.

1071

Yes, nasty copypast issue :( I think I took it from llvm\tools\llvm-objdump\MachODump.cpp or llvm\lib\MC\MCDwarf.cpp where getSizeForEncoding() have the same one..

1106

Changed message to "CIE code alignment must be 1". As CIE also has data alignment factor.

ELF/OutputSections.h
286

Its constructed from
unsigned Index = S->Offsets.size();
...
Cie<ELFT> C(S, Index);
So it seems more correct would be to use size_t instead of unsigned. But I guess its not possible in real life to have overflow here (its hard to imagine).

ruiu accepted this revision.Jan 13 2016, 12:22 PM
ruiu edited edge metadata.

LGTM with a few nits.

ELF/OutputSections.cpp
929–930

Write this in one line.

937

It is odd that we are using uintX_t here but we write it as a 32-bit integer. Shouldn't we just use uint32_t here?

940

Ditto

1064

format -> Format

1112
else if (Version == 3) -> else

because we know that it's always 3.

ELF/OutputSections.h
436

Please move this above the definition of align.

This revision is now accepted and ready to land.Jan 13 2016, 12:22 PM
grimar added inline comments.Jan 13 2016, 2:39 PM
ELF/OutputSections.cpp
940

What about eliminating them ?

  for (auto &I : PcToOffset) {
    // The first four bytes are an offset to the initial PC value for the FDE.
    write32<E>(Buf, I.first - VA);
    // The last four bytes are an offset to the FDE data itself.
    write32<E>(Buf + 4, EhVA + I.second - VA);
    Buf += 8;
  }
}
ruiu added inline comments.Jan 13 2016, 2:40 PM
ELF/OutputSections.cpp
940

LGTM

grimar added inline comments.Jan 13 2016, 2:50 PM
ELF/OutputSections.cpp
940

Nice. Thanks for review ! I'll commit this tomorrow.

This revision was automatically updated to reflect the committed changes.
grimar marked 9 inline comments as done.
grimar added inline comments.Jan 14 2016, 2:34 AM
ELF/OutputSections.cpp
1064

Replaced with

switch (Enc & 0x0f) {
ELF/OutputSections.h
471

I renamed class EhFrameHdr to EhFrameHeader because of compile error under linux here.