diff --git a/llvm/test/tools/llvm-objcopy/ELF/only-keep-debug.test b/llvm/test/tools/llvm-objcopy/ELF/only-keep-debug.test --- a/llvm/test/tools/llvm-objcopy/ELF/only-keep-debug.test +++ b/llvm/test/tools/llvm-objcopy/ELF/only-keep-debug.test @@ -222,3 +222,73 @@ Flags: [ SHF_ALLOC ] DynamicSymbols: [] Symbols: [] + +## PT_TLS and .tdata are empty. Test that we still attribute .tdata to PT_TLS +## and rewrite p_offset of PT_TLS. +## If we don't rewrite p_offset of PT_TLS and the deleted bytes are large, +## p_offset can be larger than the file size, and trigger validation errors. +# RUN: yaml2obj --docnum=4 %s -o %t4 +# RUN: llvm-objcopy --only-keep-debug %t4 %t4.dbg +# RUN: llvm-readelf -S -l %t4.dbg | FileCheck --check-prefix=CHECK4 %s + +# CHECK4: [Nr] Name Type Address Off Size ES Flg Lk Inf Al +# CHECK4: [ 1] .note NOTE 0000000000000200 000200 000001 00 A 0 0 512 +# CHECK4-NEXT: [ 2] .text NOBITS 0000000000000201 000201 000001 00 AX 0 0 0 +# CHECK4-NEXT: [ 3] .tdata NOBITS 0000000000001240 000240 000000 00 WAT 0 0 64 +# CHECK4-NEXT: [ 4] .got NOBITS 0000000000001240 000240 000008 00 WA 0 0 0 + +# CHECK4: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align +# CHECK4-NEXT: LOAD 0x000200 0x0000000000000200 0x0000000000000000 0x000001 0x000002 R E 0x1000 +# CHECK4-NEXT: LOAD 0x000240 0x0000000000001240 0x0000000000000000 0x000000 0x000008 RW 0x1000 +# CHECK4-NEXT: TLS 0x000240 0x0000000000001240 0x0000000000000000 0x000000 0x000000 R 0x40 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 +Sections: + - Name: .note + Type: SHT_NOTE + Flags: [ SHF_ALLOC ] + Address: 0x200 + AddressAlign: 0x200 + Size: 1 + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Address: 0x201 + Size: 1 + - Name: .tdata + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_WRITE, SHF_TLS ] + Address: 0x1240 # Ensure Address=0x1000+Offset + AddressAlign: 0x40 + - Name: .got + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_WRITE ] + Address: 0x1240 + Size: 8 +DynamicSymbols: [] +Symbols: [] +ProgramHeaders: + - Type: PT_LOAD + Flags: [ PF_R, PF_X ] + VAddr: 0x200 + Align: 0x1000 + Sections: + - Section: .note + - Section: .text + - Type: PT_LOAD + Flags: [ PF_R, PF_W ] + VAddr: 0x1240 + Align: 0x1000 + Sections: + - Section: .tdata + - Section: .got + - Type: PT_TLS + Flags: [ PF_R ] + VAddr: 0x1240 + Sections: + - Section: .tdata diff --git a/llvm/test/tools/llvm-objcopy/ELF/strip-all.test b/llvm/test/tools/llvm-objcopy/ELF/strip-all.test --- a/llvm/test/tools/llvm-objcopy/ELF/strip-all.test +++ b/llvm/test/tools/llvm-objcopy/ELF/strip-all.test @@ -74,10 +74,11 @@ Sections: - Section: non_alloc_in_segment -# CHECK: SectionHeaderCount: 6 +# CHECK: SectionHeaderCount: 7 # CHECK: Name: non_alloc_in_segment # CHECK: Name: .bss # CHECK: Name: .text +# CHECK: Name: .blarg # CHECK: Name: .gnu.warning.foo # CHECK: Name: .shstrtab diff --git a/llvm/test/tools/llvm-objcopy/ELF/strip-non-alloc.test b/llvm/test/tools/llvm-objcopy/ELF/strip-non-alloc.test --- a/llvm/test/tools/llvm-objcopy/ELF/strip-non-alloc.test +++ b/llvm/test/tools/llvm-objcopy/ELF/strip-non-alloc.test @@ -36,8 +36,9 @@ # RUN: llvm-objcopy --strip-non-alloc %t2 %t2.out # RUN: llvm-readobj --file-headers --sections %t2.out | FileCheck --check-prefix=CHECK2 %s -# CHECK2: SectionHeaderCount: 3 +# CHECK2: SectionHeaderCount: 4 # CHECK2: Name: .text +# CHECK2: Name: empty_trailing_non_alloc # CHECK2: Name: .shstrtab --- diff --git a/llvm/tools/llvm-objcopy/ELF/Object.cpp b/llvm/tools/llvm-objcopy/ELF/Object.cpp --- a/llvm/tools/llvm-objcopy/ELF/Object.cpp +++ b/llvm/tools/llvm-objcopy/ELF/Object.cpp @@ -1057,14 +1057,10 @@ Visitor.visit(*this); } -// Returns true IFF a section is wholly inside the range of a segment +// Returns true IFF a section is wholly inside the range of a segment. A section +// can be included by multiple nested segments. If an empty section lies on the +// boundary between two segments, it will be attributed to both segments. static bool sectionWithinSegment(const SectionBase &Sec, const Segment &Seg) { - // If a section is empty it should be treated like it has a size of 1. This is - // to clarify the case when an empty section lies on a boundary between two - // segments and ensures that the section "belongs" to the second segment and - // not the first. - uint64_t SecSize = Sec.Size ? Sec.Size : 1; - if (Sec.Type == SHT_NOBITS) { if (!(Sec.Flags & SHF_ALLOC)) return false; @@ -1075,11 +1071,11 @@ return false; return Seg.VAddr <= Sec.Addr && - Seg.VAddr + Seg.MemSize >= Sec.Addr + SecSize; + Seg.VAddr + Seg.MemSize >= Sec.Addr + Sec.Size; } return Seg.Offset <= Sec.OriginalOffset && - Seg.Offset + Seg.FileSize >= Sec.OriginalOffset + SecSize; + Seg.Offset + Seg.FileSize >= Sec.OriginalOffset + Sec.Size; } // Returns true IFF a segment's original offset is inside of another segment's @@ -1292,7 +1288,7 @@ for (SectionBase &Sec : Obj.sections()) if (sectionWithinSegment(Sec, Seg)) { Seg.addSection(&Sec); - if (!Sec.ParentSegment || Sec.ParentSegment->Offset > Seg.Offset) + if (!Sec.ParentSegment || Seg.Offset > Sec.ParentSegment->Offset) Sec.ParentSegment = &Seg; } }