diff --git a/llvm/test/tools/llvm-objcopy/ELF/static-rela-with-alloc.test b/llvm/test/tools/llvm-objcopy/ELF/static-rela-with-alloc.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/ELF/static-rela-with-alloc.test @@ -0,0 +1,45 @@ +# RUN: yaml2obj %s -o %t +# RUN: llvm-strip --strip-debug %t + +# +# Check that llvm-objcopy does not assume that any SHT_RELA section with the +# SHF_ALLOC set is a dynamic relocation section, as there are corner cases +# where this assumption may not hold. (e.g., the Linux kernel, which uses +# partially linked ET_REL ELF objects as its loadable module format) +# + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Address: 0x1000 + AddressAlign: 0x0000000000000010 + Size: 64 + - Name: .rela.text + Type: SHT_RELA + Flags: [ SHF_ALLOC, SHF_INFO_LINK ] + Info: .text +Symbols: + - Name: foo + Type: STT_FUNC + Section: .text + Value: 0x1000 + Size: 8 + - Name: bar + Type: STT_FUNC + Section: .text + Value: 0x1008 + Size: 8 + - Name: baz + Type: STT_FUNC + Section: .text + Value: 0x1010 + Size: 8 + + 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 @@ -1415,12 +1415,26 @@ } template Error ELFBuilder::findEhdrOffset() { + uint32_t Index = 0; if (!ExtractPartition) return Error::success(); - for (const SectionBase &Sec : Obj.sections()) { - if (Sec.Type == SHT_LLVM_PART_EHDR && Sec.Name == *ExtractPartition) { - EhdrOffset = Sec.Offset; + Expected::Elf_Shdr_Range> Sections = + ElfFile.sections(); + if (!Sections) + return Sections.takeError(); + + for (const typename ELFFile::Elf_Shdr &Shdr : *Sections) { + if (Index == 0) { + ++Index; + continue; + } + Expected SecName = ElfFile.getSectionName(Shdr); + if (!SecName) + return SecName.takeError(); + if (Shdr.sh_type == SHT_LLVM_PART_EHDR && + SecName->str() == *ExtractPartition) { + EhdrOffset = Shdr.sh_offset; return Error::success(); } } @@ -1692,7 +1706,7 @@ switch (Shdr.sh_type) { case SHT_REL: case SHT_RELA: - if (Shdr.sh_flags & SHF_ALLOC) { + if (Obj.Type != ELF::ET_REL && (Shdr.sh_flags & SHF_ALLOC)) { if (Expected> Data = ElfFile.getSectionContents(Shdr)) return Obj.addSection(*Data); else @@ -1900,8 +1914,6 @@ } template Error ELFBuilder::build(bool EnsureSymtab) { - if (Error E = readSectionHeaders()) - return E; if (Error E = findEhdrOffset()) return E; @@ -1922,6 +1934,8 @@ Obj.Entry = Ehdr.e_entry; Obj.Flags = Ehdr.e_flags; + if (Error E = readSectionHeaders()) + return E; if (Error E = readSections(EnsureSymtab)) return E; return readProgramHeaders(*HeadersFile);