Index: llvm/lib/ObjectYAML/ELFEmitter.cpp =================================================================== --- llvm/lib/ObjectYAML/ELFEmitter.cpp +++ llvm/lib/ObjectYAML/ELFEmitter.cpp @@ -1063,13 +1063,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 @@ -140,3 +140,168 @@ - Section: .nobits.1 - Section: .data - Section: .nobits.2 + +## Here we test that yaml2obj is able to handle SHT_NOBITS sections in segments properly. + +## Set the file offset for segments to 0x0. +## Set VAddr of segments to 0x200000000 == VA of .nobits1(0x2000001c8) minus its offset. +# RUN: yaml2obj %s --docnum=3 -DOFFSET=0x0 -DVADDR=0x200000000 -o %t5 +# RUN: llvm-readelf --sections --segments %t5 | 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=3 -DOFFSET=0x1c8 -DVADDR=0x2000001c8 -o %t6 +# RUN: llvm-readelf --sections --segments %t6 | 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 00000002000001c8 0001c8 000001 +# COMMON-NEXT: [ 2] .progbits1 PROGBITS 00000002000001c9 0001c9 000001 +# COMMON-NEXT: [ 3] .progbits2 PROGBITS 00000002000001d0 0001d0 000010 +# COMMON-NEXT: [ 4] .nobits2 NOBITS 00000002000001e0 0001e0 000020 +## The .filler chunk (size = 0x90) is placed here. +# COMMON-NEXT: [ 5] .nobits3 NOBITS 0000000200000290 000290 0001d0 +# COMMON-NEXT: [ 6] .nobits4 NOBITS 0000000200000460 000290 000100 +# COMMON-NEXT: [ 7] .strtab STRTAB 0000000000000000 000290 000001 + +# COMMON: Type Offset VirtAddr PhysAddr FileSiz MemSiz +## This segment includes sections 1 to 6. +# NOOFFSET-NEXT: LOAD 0x000000 0x0000000200000000 0x0000000200000000 0x000290 0x000560 +# OFFSET-NEXT: LOAD 0x0001c8 0x00000002000001c8 0x00000002000001c8 0x0000c8 0x000398 +## This segment includes sections 1 to 5. +# NOOFFSET-NEXT: LOAD 0x000000 0x0000000200000000 0x0000000200000000 0x000290 0x000460 +# OFFSET-NEXT: LOAD 0x0001c8 0x00000002000001c8 0x00000002000001c8 0x0000c8 0x000298 +## This segment includes sections 1 to 4 + the .filler chunk. +# NOOFFSET-NEXT: LOAD 0x000000 0x0000000200000000 0x0000000200000000 0x000290 0x000290 +# OFFSET-NEXT: LOAD 0x0001c8 0x00000002000001c8 0x00000002000001c8 0x0000c8 0x0000c8 +## This segment includes the first four sections. +# NOOFFSET-NEXT: LOAD 0x000000 0x0000000200000000 0x0000000200000000 0x0001e0 0x000200 +# OFFSET-NEXT: LOAD 0x0001c8 0x00000002000001c8 0x00000002000001c8 0x000018 0x000038 +## This segment includes the first three sections. +# NOOFFSET-NEXT: LOAD 0x000000 0x0000000200000000 0x0000000200000000 0x0001e0 0x0001e0 +# OFFSET-NEXT: LOAD 0x0001c8 0x00000002000001c8 0x00000002000001c8 0x000018 0x000018 +## This segment includes the first two sections. +# NOOFFSET-NEXT: LOAD 0x000000 0x0000000200000000 0x0000000200000000 0x0001ca 0x0001ca +# OFFSET-NEXT: LOAD 0x0001c8 0x00000002000001c8 0x00000002000001c8 0x000002 0x000002 +## This segment includes the first section only. +# NOOFFSET-NEXT: LOAD 0x000000 0x0000000200000000 0x0000000200000000 0x0001c8 0x0001c9 +# OFFSET-NEXT: LOAD 0x0001c8 0x00000002000001c8 0x00000002000001c8 0x000000 0x000001 + +--- !ELF +FileHeader: + 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 + Sections: + - 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 that includes first 4 sections. It is easier to verify +## memory and file size calculations with it. + - Type: PT_LOAD + Sections: + - Section: .nobits1 + - Section: .progbits1 + - Section: .progbits2 + - Section: .nobits2 + VAddr: [[VADDR]] + Offset: [[OFFSET]] +## A segment that includes first 3 sections. It is easier to verify +## memory and file size calculations with it. + - Type: PT_LOAD + Sections: + - Section: .nobits1 + - Section: .progbits1 + - Section: .progbits2 + 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: 0x2000001c8 + - 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