Index: llvm/lib/ObjectYAML/ELFEmitter.cpp =================================================================== --- llvm/lib/ObjectYAML/ELFEmitter.cpp +++ llvm/lib/ObjectYAML/ELFEmitter.cpp @@ -784,13 +784,27 @@ PHeader.p_filesz = FileSize; } - // Find the maximum offset of the end of a section in order to set p_memsz. - uint64_t MemOffset = PHeader.p_offset; - for (const Fragment &F : Fragments) - MemOffset = std::max(MemOffset, F.Offset + F.Size); // Set the memory size if not set explicitly. - PHeader.p_memsz = YamlPhdr.MemSize ? uint64_t(*YamlPhdr.MemSize) - : MemOffset - PHeader.p_offset; + if (YamlPhdr.MemSize) { + PHeader.p_memsz = *YamlPhdr.MemSize; + } else if (!Fragments.empty()) { + uint64_t MemSize = Fragments.front().Offset - PHeader.p_offset; + for (size_t I = 0, E = Fragments.size(); I != E; ++I) { + const Fragment &Cur = Fragments[I]; + const Fragment *Next = (I + 1 < E) ? &Fragments[I + 1] : nullptr; + + // The distance between the current and the next section can + // be larger than the size of the current section when there is a gap + // due to alignment, or when we have 2 or more trailing SHT_NOBITS + // sections with the same offset. In the latter case, we should take all + // trailing SHT_NOBITS section sizes into account. + if (Next) + MemSize += std::max(Next->Offset - Cur.Offset, Cur.Size); + else + MemSize += Cur.Size; + } + PHeader.p_memsz = MemSize; + } if (YamlPhdr.Align) { PHeader.p_align = *YamlPhdr.Align; Index: llvm/test/tools/yaml2obj/ELF/program-header-nobits.yaml =================================================================== --- llvm/test/tools/yaml2obj/ELF/program-header-nobits.yaml +++ llvm/test/tools/yaml2obj/ELF/program-header-nobits.yaml @@ -1,39 +1,139 @@ -# RUN: yaml2obj %s -o %t -# RUN: llvm-readobj -l %t | FileCheck %s +## Here we test that yaml2obj is able to handle SHT_NOBITS sections in segments properly. -!ELF +## Set the file offset for segments to 0x0. +# RUN: yaml2obj %s --docnum=1 -DOFFSET=0x0 -o %t1 +# RUN: llvm-readelf --sections --segments %t1 | FileCheck %s --check-prefixes=COMMON,NOOFFSET + +## Set file offsets of segments to the offset of the first section to show +## that with a non-zero offset we still calculate memory and file sizes properly. +# RUN: yaml2obj %s --docnum=1 -DOFFSET=0x158 -o %t2 +# RUN: llvm-readelf --sections --segments %t2 | FileCheck %s --check-prefixes=COMMON,OFFSET + +# COMMON: Section Headers: +# COMMON-NEXT: [Nr] Name Type Address Off Size +# COMMON-NEXT: [ 0] NULL 0000000000000000 000000 000000 +# COMMON-NEXT: [ 1] .nobits1 NOBITS 00000001fffffea8 000158 000010 +# COMMON-NEXT: [ 2] .progbits1 PROGBITS 00000001fffffeb8 000158 000001 +# COMMON-NEXT: [ 3] .progbits2 PROGBITS 00000001fffffec0 000160 000010 +# COMMON-NEXT: [ 4] .nobits2 NOBITS 00000001fffffed0 000170 000020 +## The .filler chunk (size = 0x90) is placed here. +# COMMON-NEXT: [ 5] .nobits3 NOBITS 00000001ffffff80 000200 0001d0 +# COMMON-NEXT: [ 6] .nobits4 NOBITS 0000000200000150 000200 000100 +# COMMON-NEXT: [ 7] .strtab STRTAB 0000000000000000 000200 000001 + +# COMMON: Type Offset VirtAddr PhysAddr FileSiz MemSiz +## This segment includes sections 1 to 6. +# NOOFFSET-NEXT: LOAD 0x000000 0x00000001fffffea8 0x00000001fffffea8 0x000200 0x000500 +# OFFSET-NEXT: LOAD 0x000158 0x00000001fffffea8 0x00000001fffffea8 0x0000a8 0x0003a8 +## This segment includes sections 1 to 5. +# NOOFFSET-NEXT: LOAD 0x000000 0x00000001fffffea8 0x00000001fffffea8 0x000200 0x000400 +# OFFSET-NEXT: LOAD 0x000158 0x00000001fffffea8 0x00000001fffffea8 0x0000a8 0x0002a8 +## This segment includes sections 1 to 4 + the .filler chunk. +# NOOFFSET-NEXT: LOAD 0x000000 0x00000001fffffea8 0x00000001fffffea8 0x000200 0x000230 +# OFFSET-NEXT: LOAD 0x000158 0x00000001fffffea8 0x00000001fffffea8 0x0000a8 0x0000d8 +## This segment includes the first two sections. +# NOOFFSET-NEXT: LOAD 0x000000 0x00000001fffffea8 0x00000001fffffea8 0x000159 0x000169 +# OFFSET-NEXT: LOAD 0x000158 0x00000001fffffea8 0x00000001fffffea8 0x000001 0x000011 +## This segment includes the first section only. +# NOOFFSET-NEXT: LOAD 0x000000 0x00000001fffffea8 0x00000001fffffea8 0x000158 0x000168 +# OFFSET-NEXT: LOAD 0x000158 0x00000001fffffea8 0x00000001fffffea8 0x000000 0x000010 + +--- !ELF FileHeader: - Class: ELFCLASS64 - Data: ELFDATA2LSB - Type: ET_EXEC - Machine: EM_X86_64 -Sections: - - Name: .data - Type: SHT_PROGBITS - Flags: [ SHF_ALLOC ] - Content: "00000000" - - Name: .after - Type: SHT_NOBITS - Flags: [ SHF_ALLOC ] - Size: 64 + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 ProgramHeaders: - - Type: PT_LOAD - Flags: [ PF_R ] +## A segment that has all the sections included and has +## two SHT_NOBITS sections at the end. + - Type: PT_LOAD Sections: - - Section: .data - - Section: .after - -#CHECK: ProgramHeaders [ -#CHECK-NEXT: ProgramHeader { -#CHECK-NEXT: Type: PT_LOAD -#CHECK-NEXT: Offset: -#CHECK-NEXT: VirtualAddress: -#CHECK-NEXT: PhysicalAddress: -#CHECK-NEXT: FileSize: 4 -#CHECK-NEXT: MemSize: 68 -#CHECK-NEXT: Flags [ -#CHECK-NEXT: PF_R -#CHECK-NEXT: ] -#CHECK-NEXT: Alignment: -#CHECK-NEXT: } -#CHECK-NEXT:] + - Section: .nobits1 + - Section: .progbits1 + - Section: .progbits2 + - Section: .nobits2 + - Section: .filler + - Section: .nobits3 + - Section: .nobits4 +## Here and below: 0x1FFFFFEA8 == VA of .nobits1(0x200000000) - its offset. + VAddr: 0x1FFFFFEA8 + Offset: [[OFFSET]] +## A segment with SHT_NOBITS sections and a single +## SHT_PROGBITS section at the end. + - Type: PT_LOAD + Sections: + - Section: .nobits1 + - Section: .progbits1 + - Section: .progbits2 + - Section: .nobits2 + - Section: .filler + - Section: .nobits3 + VAddr: 0x1FFFFFEA8 + Offset: [[OFFSET]] +## A segment with SHT_NOBITS sections and a Fill +## chunk at the end. + - Type: PT_LOAD + Sections: + - Section: .nobits1 + - Section: .progbits1 + - Section: .progbits2 + - Section: .nobits2 + - Section: .filler + VAddr: 0x1FFFFFEA8 + Offset: [[OFFSET]] +## A segment with a SHT_NOBITS section and a +## SHT_PROGBITS section at the end. + - Type: PT_LOAD + Sections: + - Section: .nobits1 + - Section: .progbits1 + VAddr: 0x1FFFFFEA8 + Offset: [[OFFSET]] +## A segment with only SHT_NOBITS section. + - Type: PT_LOAD + Sections: + - Section: .nobits1 + VAddr: 0x1FFFFFEA8 + Offset: [[OFFSET]] +Sections: +## We have a SHT_NOBITS section at the start. + - Name: .nobits1 + Type: SHT_NOBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + Size: 0x10 + Address: 0x1FFFFFEA8 + - Name: .progbits1 +## It is followed by two SHT_PROGBITS sections. Note that the virtual +## address of .progbits2 is aligned so that there is an alignment gap +## between .progbits1 and .progbits2 sections. + Type: SHT_PROGBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + Size: 0x1 + - Name: .progbits2 + Type: SHT_PROGBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + Size: 0x10 + AddressAlign: 0x10 +## We have a SHT_NOBITS section in the middle. + - Name: .nobits2 + Type: SHT_NOBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + Size: 0x20 +## We have a Fill chunk. + - Type: Fill + Name: .filler + Pattern: "CCDD" + Size: 0x90 +## We have two SHT_NOBITS sections at the end. +## It is important to have at least two of them because we had a bug +## related to an incorrect computation of the memory size of a segment when +## there were multiple SHT_NOBITS sections at the end. + - Name: .nobits3 + Type: SHT_NOBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + Size: 0x1D0 + - Name: .nobits4 + Type: SHT_NOBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + Size: 0x100