diff --git a/llvm/test/tools/llvm-objcopy/MachO/relocations.test b/llvm/test/tools/llvm-objcopy/MachO/relocations.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/MachO/relocations.test @@ -0,0 +1,95 @@ +# RUN: yaml2obj %s -o %t + +## Show that llvm-objcopy copies relocation entries where r_extern = 0. +# RUN: llvm-objcopy %t %t2 +# RUN: cmp %t %t2 + +## Show that llvm-objcopy updates section indices properly. +# RUN: llvm-objcopy --remove-section=__DATA,__foo %t %t3 +# RUN: llvm-objdump --macho --reloc %t3 | FileCheck %s + +# CHECK: Relocation information (__DATA,__bar) 2 entries +# CHECK-NEXT: address pcrel length extern type scattered symbolnum/value +# CHECK-NEXT: 00000000 False quad False SUB False 2 (__DATA,__bar) +# CHECK-NEXT: 00000000 False quad False UNSIGND False 1 (__TEXT,__text) + +--- !mach-o +FileHeader: + magic: 0xFEEDFACF + cputype: 0x01000007 + cpusubtype: 0x00000003 + filetype: 0x00000001 + ncmds: 1 + sizeofcmds: 312 + flags: 0x00000000 + reserved: 0x00000000 +LoadCommands: + - cmd: LC_SEGMENT_64 + cmdsize: 312 + segname: '' + vmaddr: 0 + vmsize: 24 + fileoff: 344 + filesize: 24 + maxprot: 7 + initprot: 7 + nsects: 3 + flags: 0 + Sections: + - sectname: __text + segname: __TEXT + addr: 0x0000000000000000 + size: 8 + offset: 0x00000158 + align: 0 + reloff: 0x00000000 + nreloc: 0 + flags: 0x80000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + content: '0000000000000000' + - sectname: __foo + segname: __DATA + addr: 0x0000000000000008 + size: 8 + offset: 0x00000160 + align: 0 + reloff: 0x00000000 + nreloc: 0 + flags: 0x00000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + content: '0000000000000000' + - sectname: __bar + segname: __DATA + addr: 0x0000000000000010 + size: 8 + offset: 0x00000168 + align: 0 + reloff: 0x00000170 + nreloc: 2 + flags: 0x00000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + content: F0FFFFFFFFFFFFFF + relocations: + - address: 0x00000000 + symbolnum: 3 + pcrel: false + length: 3 + extern: false + type: 5 + scattered: false + value: 0 + - address: 0x00000000 + symbolnum: 1 + pcrel: false + length: 3 + extern: false + type: 0 + scattered: false + value: 0 +... diff --git a/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp b/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp --- a/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp +++ b/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp @@ -103,6 +103,7 @@ R.Symbol = nullptr; // We'll fill this field later. R.Info = MachOObj.getRelocation(RI->getRawDataRefImpl()); R.Scattered = MachOObj.isRelocationScattered(R.Info); + R.Extern = !R.Scattered && MachOObj.getPlainRelocationExternal(R.Info); S.Relocations.push_back(R); } @@ -203,12 +204,27 @@ } void MachOReader::setSymbolInRelocationInfo(Object &O) const { + std::vector Sections; + for (auto &LC : O.LoadCommands) + for (std::unique_ptr
&Sec : LC.Sections) + Sections.push_back(Sec.get()); + for (LoadCommand &LC : O.LoadCommands) for (std::unique_ptr
&Sec : LC.Sections) for (auto &Reloc : Sec->Relocations) - if (!Reloc.Scattered) - Reloc.Symbol = O.SymTable.getSymbolByIndex( - Reloc.getPlainRelocationSymbolNum(MachOObj.isLittleEndian())); + if (!Reloc.Scattered) { + const uint32_t SymbolNum = + Reloc.getPlainRelocationSymbolNum(MachOObj.isLittleEndian()); + if (Reloc.Extern) { + Reloc.Symbol = O.SymTable.getSymbolByIndex(SymbolNum); + } else { + // FIXME: Refactor error handling in MachOReader and report an error + // if we encounter an invalid relocation. + assert(SymbolNum >= 1 && SymbolNum <= Sections.size() && + "Invalid section index."); + Reloc.Section = Sections[SymbolNum - 1]; + } + } } void MachOReader::readRebaseInfo(Object &O) const { diff --git a/llvm/tools/llvm-objcopy/MachO/MachOWriter.cpp b/llvm/tools/llvm-objcopy/MachO/MachOWriter.cpp --- a/llvm/tools/llvm-objcopy/MachO/MachOWriter.cpp +++ b/llvm/tools/llvm-objcopy/MachO/MachOWriter.cpp @@ -239,11 +239,13 @@ memcpy(B.getBufferStart() + Sec->Offset, Sec->Content.data(), Sec->Content.size()); for (size_t Index = 0; Index < Sec->Relocations.size(); ++Index) { - auto RelocInfo = Sec->Relocations[Index]; - if (!RelocInfo.Scattered) - RelocInfo.setPlainRelocationSymbolNum(RelocInfo.Symbol->Index, - IsLittleEndian); - + RelocationInfo RelocInfo = Sec->Relocations[Index]; + if (!RelocInfo.Scattered) { + const uint32_t SymbolNum = RelocInfo.Extern + ? (*RelocInfo.Symbol)->Index + : (*RelocInfo.Section)->Index; + RelocInfo.setPlainRelocationSymbolNum(SymbolNum, IsLittleEndian); + } if (IsLittleEndian != sys::IsLittleEndianHost) MachO::swapStruct( reinterpret_cast(RelocInfo.Info)); diff --git a/llvm/tools/llvm-objcopy/MachO/Object.h b/llvm/tools/llvm-objcopy/MachO/Object.h --- a/llvm/tools/llvm-objcopy/MachO/Object.h +++ b/llvm/tools/llvm-objcopy/MachO/Object.h @@ -162,9 +162,14 @@ }; struct RelocationInfo { - const SymbolEntry *Symbol; + // The referenced symbol entry. Set if !Scattered && Extern. + Optional Symbol; + // The referenced section. Set if !Scattered && !Extern. + Optional Section; // True if Info is a scattered_relocation_info. bool Scattered; + // True if the r_symbolnum points to a section number (i.e. r_extern=0). + bool Extern; MachO::any_relocation_info Info; unsigned getPlainRelocationSymbolNum(bool IsLittleEndian) { diff --git a/llvm/tools/llvm-objcopy/MachO/Object.cpp b/llvm/tools/llvm-objcopy/MachO/Object.cpp --- a/llvm/tools/llvm-objcopy/MachO/Object.cpp +++ b/llvm/tools/llvm-objcopy/MachO/Object.cpp @@ -60,13 +60,13 @@ for (const LoadCommand &LC : LoadCommands) for (const std::unique_ptr
&Sec : LC.Sections) for (const RelocationInfo &R : Sec->Relocations) - if (R.Symbol && DeadSymbols.count(R.Symbol)) + if (R.Symbol && *R.Symbol && DeadSymbols.count(*R.Symbol)) return createStringError(std::errc::invalid_argument, "symbol '%s' defined in section with index " "'%u' cannot be removed because it is " "referenced by a relocation in section '%s'", - R.Symbol->Name.c_str(), - *(R.Symbol->section()), + (*R.Symbol)->Name.c_str(), + *((*R.Symbol)->section()), Sec->CanonicalName.c_str()); SymTable.removeSymbols(IsDead); for (std::unique_ptr &S : SymTable.Symbols)