Index: test/tools/llvm-objcopy/COFF/bigobj.test =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/COFF/bigobj.test @@ -0,0 +1,59 @@ +# RUN: yaml2obj %s > %t.in.o +# +# RUN: llvm-objdump -t %t.in.o | FileCheck %s --check-prefixes=SYMBOLS,SYMBOLS-SMALL +# +# RUN: llvm-objcopy --force-bigobj %t.in.o %t.big.o +# RUN: llvm-objdump -t %t.big.o | FileCheck %s --check-prefixes=SYMBOLS,SYMBOLS-BIG +# RUN: llvm-objcopy %t.big.o %t.small.o +# RUN: llvm-objdump -t %t.small.o | FileCheck %s --check-prefixes=SYMBOLS,SYMBOLS-SMALL + +# SYMBOLS: SYMBOL TABLE: +# SYMBOLS-NEXT: [ 0]{{.*}} (nx 1) {{.*}} .text +# SYMBOLS-NEXT: AUX scnlen +# SYMBOLS-SMALL-NEXT: [ 2]{{.*}} (nx 2) {{.*}} .file +# SYMBOLS-BIG-NEXT: [ 2]{{.*}} (nx 1) {{.*}} .file +# SYMBOLS-NEXT: AUX abcdefghijklmnopqrs +# SYMBOLS-SMALL-NEXT: [ 5]{{.*}} (nx 0) {{.*}} foo +# SYMBOLS-BIG-NEXT: [ 4]{{.*}} (nx 0) {{.*}} foo +# SYMBOLS-EMPTY: + +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [ ] +sections: + - Name: .text + Characteristics: [ ] + Alignment: 4 + SectionData: 488B0500000000C3 + Relocations: + - VirtualAddress: 3 + SymbolName: foo + Type: IMAGE_REL_AMD64_REL32 +symbols: + - Name: .text + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 1 + NumberOfRelocations: 1 + NumberOfLinenumbers: 0 + CheckSum: 583624169 + Number: 1 + - Name: .file + Value: 0 + SectionNumber: -2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_FILE + File: abcdefghijklmnopqrs + - Name: foo + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... Index: tools/llvm-objcopy/COFF/COFFObjcopy.cpp =================================================================== --- tools/llvm-objcopy/COFF/COFFObjcopy.cpp +++ tools/llvm-objcopy/COFF/COFFObjcopy.cpp @@ -183,7 +183,7 @@ assert(Obj && "Unable to deserialize COFF object"); if (Error E = handleArgs(Config, *Obj)) reportError(Config.InputFilename, std::move(E)); - COFFWriter Writer(*Obj, Out); + COFFWriter Writer(*Obj, Out, Config.ForceBigObj); if (Error E = Writer.write()) reportError(Config.OutputFilename, std::move(E)); } Index: tools/llvm-objcopy/COFF/Object.h =================================================================== --- tools/llvm-objcopy/COFF/Object.h +++ tools/llvm-objcopy/COFF/Object.h @@ -66,10 +66,24 @@ std::vector OwnedContents; }; +struct AuxSymbol { + AuxSymbol(ArrayRef In) { + assert(In.size() == sizeof(Opaque)); + std::copy(In.begin(), In.end(), Opaque); + } + + ArrayRef getRef() const { + return ArrayRef(Opaque, sizeof(Opaque)); + } + + uint8_t Opaque[sizeof(object::coff_symbol16)]; +}; + struct Symbol { object::coff_symbol32 Sym; StringRef Name; - std::vector AuxData; + std::vector AuxData; + StringRef AuxFile; ssize_t TargetSectionId; ssize_t AssociativeComdatTargetSectionId = 0; Optional WeakTargetSymbolId; @@ -132,7 +146,7 @@ ssize_t NextSectionUniqueId = 1; // Allow a UniqueId 0 to mean undefined. - // Update SymbolMap and RawIndex in each Symbol. + // Update SymbolMap. void updateSymbols(); // Update SectionMap and Index in each Section. Index: tools/llvm-objcopy/COFF/Object.cpp =================================================================== --- tools/llvm-objcopy/COFF/Object.cpp +++ tools/llvm-objcopy/COFF/Object.cpp @@ -26,12 +26,8 @@ void Object::updateSymbols() { SymbolMap = DenseMap(Symbols.size()); - size_t RawSymIndex = 0; - for (Symbol &Sym : Symbols) { + for (Symbol &Sym : Symbols) SymbolMap[Sym.UniqueId] = &Sym; - Sym.RawIndex = RawSymIndex; - RawSymIndex += 1 + Sym.Sym.NumberOfAuxSymbols; - } } const Symbol *Object::findSymbol(size_t UniqueId) const { Index: tools/llvm-objcopy/COFF/Reader.cpp =================================================================== --- tools/llvm-objcopy/COFF/Reader.cpp +++ tools/llvm-objcopy/COFF/Reader.cpp @@ -107,9 +107,17 @@ *reinterpret_cast(SymRef.getRawPtr())); if (auto EC = COFFObj.getSymbolName(SymRef, Sym.Name)) return errorCodeToError(EC); - Sym.AuxData = COFFObj.getSymbolAuxData(SymRef); - assert((Sym.AuxData.size() % - (IsBigObj ? sizeof(coff_symbol32) : sizeof(coff_symbol16))) == 0); + ArrayRef AuxData = COFFObj.getSymbolAuxData(SymRef); + size_t SymSize = IsBigObj ? sizeof(coff_symbol32) : sizeof(coff_symbol16); + assert(AuxData.size() == SymSize * SymRef.getNumberOfAuxSymbols()); + if (SymRef.isFileRecord()) { + Sym.AuxFile = StringRef(reinterpret_cast(AuxData.data()), + AuxData.size()) + .rtrim('\0'); + } else { + for (size_t I = 0; I < SymRef.getNumberOfAuxSymbols(); I++) + Sym.AuxData.push_back(AuxData.slice(I * SymSize, sizeof(AuxSymbol))); + } // Find the unique id of the section if (SymRef.getSectionNumber() <= 0) // Special symbol (undefined/absolute/debug) Index: tools/llvm-objcopy/COFF/Writer.h =================================================================== --- tools/llvm-objcopy/COFF/Writer.h +++ tools/llvm-objcopy/COFF/Writer.h @@ -24,17 +24,18 @@ class COFFWriter { Object &Obj; Buffer &Buf; + bool ForceBigObj; size_t FileSize; size_t FileAlignment; size_t SizeOfInitializedData; StringTableBuilder StrTabBuilder; + template std::pair finalizeSymbolTable(); Error finalizeRelocTargets(); Error finalizeSymbolContents(); void layoutSections(); size_t finalizeStringTable(); - template std::pair finalizeSymbolTable(); Error finalize(bool IsBigObj); @@ -50,8 +51,9 @@ virtual ~COFFWriter() {} Error write(); - COFFWriter(Object &Obj, Buffer &Buf) - : Obj(Obj), Buf(Buf), StrTabBuilder(StringTableBuilder::WinCOFF) {} + COFFWriter(Object &Obj, Buffer &Buf, bool ForceBigObj = false) + : Obj(Obj), Buf(Buf), ForceBigObj(ForceBigObj), + StrTabBuilder(StringTableBuilder::WinCOFF) {} }; } // end namespace coff Index: tools/llvm-objcopy/COFF/Writer.cpp =================================================================== --- tools/llvm-objcopy/COFF/Writer.cpp +++ tools/llvm-objcopy/COFF/Writer.cpp @@ -55,7 +55,8 @@ if (Sym.Sym.NumberOfAuxSymbols == 1 && Sym.Sym.StorageClass == IMAGE_SYM_CLASS_STATIC) { coff_aux_section_definition *SD = - reinterpret_cast(Sym.AuxData.data()); + reinterpret_cast( + Sym.AuxData[0].Opaque); uint32_t SDSectionNumber; if (Sym.AssociativeComdatTargetSectionId == 0) { // Not a comdat associative section; just set the Number field to @@ -79,7 +80,7 @@ // we want to set. Only >= 1 would be required, but only == 1 makes sense. if (Sym.WeakTargetSymbolId && Sym.Sym.NumberOfAuxSymbols == 1) { coff_aux_weak_external *WE = - reinterpret_cast(Sym.AuxData.data()); + reinterpret_cast(Sym.AuxData[0].Opaque); const Symbol *Target = Obj.findSymbol(*Sym.WeakTargetSymbolId); if (Target == nullptr) return createStringError(object_error::invalid_symbol_index, @@ -140,13 +141,23 @@ template std::pair COFFWriter::finalizeSymbolTable() { - size_t SymTabSize = Obj.getSymbols().size() * sizeof(SymbolTy); - for (const auto &S : Obj.getSymbols()) - SymTabSize += S.AuxData.size(); - return std::make_pair(SymTabSize, sizeof(SymbolTy)); + size_t RawSymIndex = 0; + for (auto &S : Obj.getMutableSymbols()) { + if (!S.AuxFile.empty()) + S.Sym.NumberOfAuxSymbols = + alignTo(S.AuxFile.size(), sizeof(SymbolTy)) / sizeof(SymbolTy); + S.RawIndex = RawSymIndex; + RawSymIndex += 1 + S.Sym.NumberOfAuxSymbols; + } + return std::make_pair(RawSymIndex * sizeof(SymbolTy), sizeof(SymbolTy)); } Error COFFWriter::finalize(bool IsBigObj) { + size_t SymTabSize, SymbolSize; + std::tie(SymTabSize, SymbolSize) = IsBigObj + ? finalizeSymbolTable() + : finalizeSymbolTable(); + if (Error E = finalizeRelocTargets()) return E; if (Error E = finalizeSymbolContents()) @@ -198,10 +209,6 @@ } size_t StrTabSize = finalizeStringTable(); - size_t SymTabSize, SymbolSize; - std::tie(SymTabSize, SymbolSize) = IsBigObj - ? finalizeSymbolTable() - : finalizeSymbolTable(); size_t PointerToSymbolTable = FileSize; // StrTabSize <= 4 is the size of an empty string table, only consisting @@ -311,8 +318,18 @@ copySymbol(*reinterpret_cast(Ptr), S.Sym); Ptr += sizeof(SymbolTy); - std::copy(S.AuxData.begin(), S.AuxData.end(), Ptr); - Ptr += S.AuxData.size(); + if (!S.AuxFile.empty()) { + std::copy(S.AuxFile.begin(), S.AuxFile.end(), Ptr); + // This assumes that unwritten parts of the memory mapped file + // are initialized to zero. + Ptr += S.Sym.NumberOfAuxSymbols * sizeof(SymbolTy); + } else { + for (const AuxSymbol &AuxSym : S.AuxData) { + ArrayRef Ref = AuxSym.getRef(); + std::copy(Ref.begin(), Ref.end(), Ptr); + Ptr += sizeof(SymbolTy); + } + } } if (StrTabBuilder.getSize() > 4 || !Obj.IsPE) { // Always write a string table in object files, even an empty one. @@ -378,7 +395,8 @@ } Error COFFWriter::write() { - bool IsBigObj = Obj.getSections().size() > MaxNumberOfSections16; + bool IsBigObj = + Obj.getSections().size() > MaxNumberOfSections16 || ForceBigObj; if (IsBigObj && Obj.IsPE) return createStringError(object_error::parse_failed, "Too many sections for executable"); Index: tools/llvm-objcopy/CopyConfig.h =================================================================== --- tools/llvm-objcopy/CopyConfig.h +++ tools/llvm-objcopy/CopyConfig.h @@ -93,6 +93,9 @@ bool Weaken = false; bool DecompressDebugSections = false; DebugCompressionType CompressionType = DebugCompressionType::None; + + // Options for testing only + bool ForceBigObj = false; }; // Configuration for the overall invocation of this tool. When invoked as Index: tools/llvm-objcopy/CopyConfig.cpp =================================================================== --- tools/llvm-objcopy/CopyConfig.cpp +++ tools/llvm-objcopy/CopyConfig.cpp @@ -374,6 +374,8 @@ Config.PreserveDates = InputArgs.hasArg(OBJCOPY_preserve_dates); + Config.ForceBigObj = InputArgs.hasArg(OBJCOPY_force_bigobj); + if (Config.DecompressDebugSections && Config.CompressionType != DebugCompressionType::None) { error("Cannot specify --compress-debug-sections at the same time as " Index: tools/llvm-objcopy/ObjcopyOpts.td =================================================================== --- tools/llvm-objcopy/ObjcopyOpts.td +++ tools/llvm-objcopy/ObjcopyOpts.td @@ -178,3 +178,6 @@ : Eq<"build-id-link-output", "Hard-link the output to /xx/xxx " "name derived from hex build ID">, MetaVarName<"suffix">; + +// Undocumented options only used for testing. +def force_bigobj : Flag<["--"], "force-bigobj">;