Index: llvm/lib/ObjectYAML/ELFEmitter.cpp =================================================================== --- llvm/lib/ObjectYAML/ELFEmitter.cpp +++ llvm/lib/ObjectYAML/ELFEmitter.cpp @@ -804,13 +804,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,141 @@ -# 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. +## Set VAddr of segments to 0x200000000 == VA of .nobits1(0x200000158) minus its offset. +# RUN: yaml2obj %s --docnum=1 -DOFFSET=0x0 -DVADDR=0x200000000 -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 -DVADDR=0x200000158 -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 0000000200000158 000158 000001 +# COMMON-NEXT: [ 2] .progbits1 PROGBITS 0000000200000159 000159 000001 +# COMMON-NEXT: [ 3] .progbits2 PROGBITS 0000000200000160 000160 000010 +# COMMON-NEXT: [ 4] .nobits2 NOBITS 0000000200000170 000170 000020 +## The .filler chunk (size = 0x90) is placed here. +# COMMON-NEXT: [ 5] .nobits3 NOBITS 0000000200000220 000220 0001d0 +# COMMON-NEXT: [ 6] .nobits4 NOBITS 00000002000003f0 000220 000100 +# COMMON-NEXT: [ 7] .strtab STRTAB 0000000000000000 000220 000001 + +# COMMON: Type Offset VirtAddr PhysAddr FileSiz MemSiz +## This segment includes sections 1 to 6. +# NOOFFSET-NEXT: LOAD 0x000000 0x0000000200000000 0x0000000200000000 0x000220 0x000510 +# OFFSET-NEXT: LOAD 0x000158 0x0000000200000158 0x0000000200000158 0x0000c8 0x0003b8 +## This segment includes sections 1 to 5. +# NOOFFSET-NEXT: LOAD 0x000000 0x0000000200000000 0x0000000200000000 0x000220 0x000410 +# OFFSET-NEXT: LOAD 0x000158 0x0000000200000158 0x0000000200000158 0x0000c8 0x0002b8 +## This segment includes sections 1 to 4 + the .filler chunk. +# NOOFFSET-NEXT: LOAD 0x000000 0x0000000200000000 0x0000000200000000 0x000200 0x000220 +# OFFSET-NEXT: LOAD 0x000158 0x0000000200000158 0x0000000200000158 0x0000a8 0x0000c8 +## This segment includes the first two sections. +# NOOFFSET-NEXT: LOAD 0x000000 0x0000000200000000 0x0000000200000000 0x00015a 0x00015a +# OFFSET-NEXT: LOAD 0x000158 0x0000000200000158 0x0000000200000158 0x000002 0x000002 +## This segment includes the first section only. +# NOOFFSET-NEXT: LOAD 0x000000 0x0000000200000000 0x0000000200000000 0x000158 0x000159 +# OFFSET-NEXT: LOAD 0x000158 0x0000000200000158 0x0000000200000158 0x000000 0x000001 + +--- !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: +## A segment that has all the sections included and has +## two SHT_NOBITS sections at the end. - Type: PT_LOAD - Flags: [ PF_R ] 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 + VAddr: [[VADDR]] + 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: [[VADDR]] + 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: [[VADDR]] + 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: [[VADDR]] + Offset: [[OFFSET]] +## A segment with only a SHT_NOBITS section. + - Type: PT_LOAD + Sections: + - Section: .nobits1 + VAddr: [[VADDR]] + Offset: [[OFFSET]] +Sections: +## We have a SHT_NOBITS section at the start. + - Name: .nobits1 + Type: SHT_NOBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + Size: 0x1 + Address: 0x200000158 + - 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 + Offset: 0x159 + - 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 + Offset: 0x220 + - Name: .nobits4 + Type: SHT_NOBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + Size: 0x100