This is an archive of the discontinued LLVM Phabricator instance.

[obj2yaml] Emit ProgramHeader.Offset
ClosedPublic

Authored by jobnoorman on Mar 8 2023, 1:05 AM.

Details

Summary

Currently, obj2yaml doesn't emit the offset of program headers, leaving it to yaml2obj to calculate offsets based on FirstSec and LastSec. This causes an obj2yaml->yaml2obj round trip to often produce an ELF file that is not equivalent to the original, especially since it seems common to have program headers at offset 0 whose first section starts at a higher address. Besides being non-equivalent, the produced ELF files also do not seem to work propery and readelf complains about them.

Taking a simple hello world program in C, compiled using either GCC or Clang, the original ELF file has the following program headers (only showing some relevant ones):

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000040 0x0000000000000040 0x0000000000000040
                 0x00000000000002d8 0x00000000000002d8  R      0x8
  INTERP         0x0000000000000318 0x0000000000000318 0x0000000000000318
                 0x000000000000001c 0x000000000000001c  R      0x1
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000630 0x0000000000000630  R      0x1000
  LOAD           0x0000000000001000 0x0000000000001000 0x0000000000001000
                 0x0000000000000161 0x0000000000000161  R E    0x1000
...

 Section to Segment mapping:
  Segment Sections...
   00
   01     .interp
   02     .interp .note.gnu.property .note.gnu.build-id .note.ABI-tag .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt
   03     .init .plt .text .fini
...

While this is the result of an obj2yaml->yaml2obj round trip:

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000000 0x0000000000000040 0x0000000000000040
                 0x0000000000000000 0x0000000000000000  R      0x8
readelf: Error: the PHDR segment is not covered by a LOAD segment
  INTERP         0x0000000000000318 0x0000000000000318 0x0000000000000318
                 0x000000000000001c 0x000000000000001c  R      0x1
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  LOAD           0x0000000000000318 0x0000000000000000 0x0000000000000000
                 0x0000000000000318 0x0000000000000318  R      0x1000
  LOAD           0x0000000000001000 0x0000000000001000 0x0000000000001000
                 0x0000000000000161 0x0000000000000161  R E    0x1000
...

 Section to Segment mapping:
  Segment Sections...
   00
   01     .interp
   02
   03     .init .plt .text .fini
...

Note that the offset of segment 2 changed from 0x0 to 0x318. This has two effects:

  • readelf complains "Error: the PHDR segment is not covered by a LOAD segment" since PHDR was originally covered by segment 2 but not anymore;
  • Segment 2 effectively became empty according to the section to segment mapping.

I addition to these, the output doesn't correctly execute anymore, crashing with a "SIGSEGV (Address boundary error)".

This patch fixes the difference in program header layout after a round trip by explicitly emitting offsets.

Diff Detail

Event Timeline

jobnoorman created this revision.Mar 8 2023, 1:05 AM
Herald added a project: Restricted Project. · View Herald TranscriptMar 8 2023, 1:05 AM
jobnoorman requested review of this revision.Mar 8 2023, 1:05 AM
Herald added a project: Restricted Project. · View Herald TranscriptMar 8 2023, 1:05 AM

Ping (I was just bitten by this issue again).

MaskRay accepted this revision.Sep 22 2023, 9:55 AM
This revision is now accepted and ready to land.Sep 22 2023, 9:55 AM
This revision was automatically updated to reflect the committed changes.