[PATCH] D74755: [llvm-objcopy] Attribute an empty section to a segment ending at its address

James Henderson via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Wed Feb 19 02:07:50 PST 2020


jhenderson requested changes to this revision.
jhenderson added a comment.
This revision now requires changes to proceed.

I don't think this is correct. There are a large number of parts of the existing behaviour that will be changed by this patch, and I'm not sure that's desirable. First and foremost, an empty section at the boundary point between two segments will go from being considered part of the second segmetn for layout purposes, to being in the first segment, as it impacts what segment is considered the section's parent. Here's a bit of YAML I threw together to illustrate the behaviour difference:

  --- !ELF
  FileHeader:
    Class:   ELFCLASS64
    Data:    ELFDATA2LSB
    Type:    ET_EXEC
    Machine: EM_X86_64
  Sections:
    - Name: gap
      Type: Fill
      Size: 0xE00
    - Name: .foo
      Type: SHT_PROGBITS
      Flags: [SHF_ALLOC]
      Size: 0x100
      AddressAlign: 0x100
      Address: 0
    - Name: .empty
      Type: SHT_PROGBITS
      Flags: [SHF_ALLOC]
      Address: 0x1000
    - Name: .baz
      Type: SHT_PROGBITS
      Flags: [SHF_ALLOC]
      Size: 0x100
      AddressAlign: 0x1000
      Address: 0x1000
  ProgramHeaders:
    - Type: PT_LOAD
      VAddr: 0
      PAddr: 0
      Align: 0x100
      Sections:
        - Section: .foo
    - Type: PT_LOAD
      VAddr: 0x1000
      PAddr: 0x1000
      Align: 0x1000
      Sections:
        - Section: .empty
        - Section: .baz

Both llvm-objcopy and GNU objcopy will physically move the first segment earlier in the file, to fill the gap, and all contained sections will move with it (before the patch, this is just .foo). This means that .foo ends up at offset 0x100, and .empty and .baz are left at 0x1000, since the second segment can't move due to alignment constraints. With the patch, however, .empty is considered part of the first segment, and so is moved to offset 0x200, leaving it a long way from the segment it should be in according to the address.

Whilst in general this probably doesn't matter (section headers have no impact on runtime usually, whilst an empty section has no contents so it doesn't matter where it gets moved to), I could imagine rarer cases where sections are used as some kind of marker or similar. Moving the section to a different segment might cause unintended consequences. Furthermore, the effective address of that section will change as it is now in a different segment. This might cause problems for tools that want to lookup things, based on the address.

I think a different solution needs to be found.

Additional related thought - for an empty segment that is on the boundary between two segments, which should it move with? Arguably, the segment is in neither and can be moved independently (that is what GNU objcopy does). I extended the above example to try this out, by having a segment at the same location as .empty, and the segment moved independently of the other two, but .empty remained in the final segment. Weirdly, if I made that segment a PT_TLS segment, the behaviour changed completely - the PT_TLS was moved even before the other two segments, and its Virtual Address changed to 0. This sounds a little mad, and I'm not sure we should follow it. Further experimentation showed yet another different behaviour in GNU objcopy however - if the .empty section is given the SHF_TLS flag, the PT_TLS segment does not move (i.e. it stays with the .empty section, at the start of the second segment.

My conclusion from all of this is that the solution might be to special-case TLS segments somehow. I honestly don't really know though.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D74755/new/

https://reviews.llvm.org/D74755





More information about the llvm-commits mailing list