Index: llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp =================================================================== --- llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp +++ llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp @@ -97,6 +97,14 @@ return (OldFlags & PreserveMask) | (NewFlags & ~PreserveMask); } +static void setSectionType(SectionBase &Sec, uint64_t Type) { + // If Sec's type is changed from SHT_NOBITS due to --set-section-flags, + // Offset may not be aligned. Align it to max(Align, 1). + if (Sec.Type == ELF::SHT_NOBITS && Type != ELF::SHT_NOBITS) + Sec.Offset = alignTo(Sec.Offset, std::max(Sec.Align, uint64_t(1))); + Sec.Type = Type; +} + static void setSectionFlagsAndType(SectionBase &Sec, SectionFlag Flags) { Sec.Flags = getSectionFlagsPreserveMask(Sec.Flags, getNewShfFlags(Flags)); @@ -106,7 +114,7 @@ if (Sec.Type == SHT_NOBITS && (!(Sec.Flags & ELF::SHF_ALLOC) || Flags & (SectionFlag::SecContents | SectionFlag::SecLoad))) - Sec.Type = SHT_PROGBITS; + setSectionType(Sec, ELF::SHT_PROGBITS); } static ElfType getOutputElfType(const Binary &Bin) { @@ -684,7 +692,7 @@ } auto It2 = Config.SetSectionType.find(Sec.Name); if (It2 != Config.SetSectionType.end()) - Sec.Type = It2->second; + setSectionType(Sec, It2->second); } } Index: llvm/lib/ObjCopy/ELF/ELFObject.cpp =================================================================== --- llvm/lib/ObjCopy/ELF/ELFObject.cpp +++ llvm/lib/ObjCopy/ELF/ELFObject.cpp @@ -2652,12 +2652,9 @@ // MinAddr will be skipped. uint64_t MinAddr = UINT64_MAX; for (SectionBase &Sec : Obj.allocSections()) { - // If Sec's type is changed from SHT_NOBITS due to --set-section-flags, - // Offset may not be aligned. Align it to max(Align, 1). if (Sec.ParentSegment != nullptr) - Sec.Addr = alignTo(Sec.Offset - Sec.ParentSegment->Offset + - Sec.ParentSegment->PAddr, - std::max(Sec.Align, uint64_t(1))); + Sec.Addr = + Sec.Offset - Sec.ParentSegment->Offset + Sec.ParentSegment->PAddr; if (Sec.Type != SHT_NOBITS && Sec.Size > 0) MinAddr = std::min(MinAddr, Sec.Addr); } Index: llvm/test/tools/llvm-objcopy/ELF/binary-paddr.test =================================================================== --- llvm/test/tools/llvm-objcopy/ELF/binary-paddr.test +++ llvm/test/tools/llvm-objcopy/ELF/binary-paddr.test @@ -254,3 +254,55 @@ FileSize: 0x2 MemSize: 0x13 Align: 0x1000 + +## Test that sections do not move relative to their physical addresses if +## the physical address is not aligned. This behavior matches GNU objcopy +## and is important for embedded images where the physical address is +## used to store the initial data image. Without converting the type of a +## NOBITS section, don't align the offset. This matches GNU objcopy when +## the physical address of a section is not aligned. + +# RUN: yaml2obj --docnum=8 %s -o %t8 +# RUN: llvm-objcopy -O binary --only-section=.text --only-section=.data %t8 %t8.out +# RUN: od -A x -t x1 %t8.out | FileCheck %s --check-prefix=PHYSUNALIGNED --ignore-case + +# PHYSUNALIGNED: 000000 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff 00 +# PHYSUNALIGNED-NEXT: 000010 11 22 33 44 bd ac cd ab + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +ProgramHeaders: + - Type: PT_LOAD + Flags: [ PF_X, PF_R ] + FirstSec: .text + LastSec: .text + VAddr: 0x200000 + PAddr: 0x200000 + Align: 0x1000 + - Type: PT_LOAD + Flags: [ PF_W, PF_R ] + FirstSec: .data + LastSec: .data + VAddr: 0x400000 + PAddr: 0x200014 +## PAddr is not aligned by sh_addralign(.data) + Align: 0x1000 +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Address: 0x200000 + AddressAlign: 0x1 + Offset: 0x1000 + Content: 112233445566778899aabbccddeeff0011223344 + - Name: .data + Type: SHT_PROGBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + Address: 0x400000 + AddressAlign: 0x8 + Offset: 0x2000 + Content: BDACCDAB