Index: COFF/Driver.cpp =================================================================== --- COFF/Driver.cpp +++ COFF/Driver.cpp @@ -209,6 +209,7 @@ // Symbol names are mangled by appending "_" prefix on x86. StringRef LinkerDriver::mangle(StringRef Sym) { + assert(Config->MachineType != IMAGE_FILE_MACHINE_UNKNOWN); if (Config->MachineType == IMAGE_FILE_MACHINE_I386) return Alloc.save("_" + Sym); return Sym; @@ -293,8 +294,9 @@ Config->Force = true; // Handle /entry + StringRef Entry; if (auto *Arg = Args.getLastArg(OPT_entry)) - Config->Entry = addUndefined(mangle(Arg->getValue())); + Entry = Arg->getValue(); // Handle /debug if (Args.hasArg(OPT_debug)) @@ -314,8 +316,8 @@ Config->DLL = true; Config->ImageBase = 0x180000000U; Config->ManifestID = 2; - if (Config->Entry == nullptr && !Config->NoEntry) - Config->Entry = addUndefined("_DllMainCRTStartup"); + if (Entry.empty() && !Config->NoEntry) + Entry = "_DllMainCRTStartup"; } // Handle /fixed @@ -497,21 +499,21 @@ // Create a list of input files. Files can be given as arguments // for /defaultlib option. - std::vector InputPaths; - std::vector Inputs; + std::vector Paths; + std::vector MBs; for (auto *Arg : Args.filtered(OPT_INPUT)) if (Optional Path = findFile(Arg->getValue())) - InputPaths.push_back(*Path); + Paths.push_back(*Path); for (auto *Arg : Args.filtered(OPT_defaultlib)) if (Optional Path = findLib(Arg->getValue())) - InputPaths.push_back(*Path); - for (StringRef Path : InputPaths) { + Paths.push_back(*Path); + for (StringRef Path : Paths) { ErrorOr MBOrErr = openFile(Path); if (auto EC = MBOrErr.getError()) { llvm::errs() << "cannot open " << Path << ": " << EC.message() << "\n"; return false; } - Inputs.push_back(MBOrErr.get()); + MBs.push_back(MBOrErr.get()); } // Windows specific -- Create a resource file containing a manifest file. @@ -520,42 +522,72 @@ if (MBOrErr.getError()) return false; std::unique_ptr MB = std::move(MBOrErr.get()); - Inputs.push_back(MB->getMemBufferRef()); + MBs.push_back(MB->getMemBufferRef()); OwningMBs.push_back(std::move(MB)); // take ownership } // Windows specific -- Input files can be Windows resource files (.res files). // We invoke cvtres.exe to convert resource files to a regular COFF file // then link the result file normally. + std::vector Resources; auto NotResource = [](MemoryBufferRef MB) { return identify_magic(MB.getBuffer()) != file_magic::windows_resource; }; - auto It = std::stable_partition(Inputs.begin(), Inputs.end(), NotResource); - if (It != Inputs.end()) { - std::vector Files(It, Inputs.end()); - auto MBOrErr = convertResToCOFF(Files); - if (MBOrErr.getError()) - return false; - std::unique_ptr MB = std::move(MBOrErr.get()); - Inputs.erase(It, Inputs.end()); - Inputs.push_back(MB->getMemBufferRef()); - OwningMBs.push_back(std::move(MB)); // take ownership + auto It = std::stable_partition(MBs.begin(), MBs.end(), NotResource); + if (It != MBs.end()) { + Resources.insert(Resources.end(), It, MBs.end()); + MBs.erase(It, MBs.end()); } - Symtab.addAbsolute(mangle("__ImageBase"), Config->ImageBase); - // Read all input files given via the command line. Note that step() // doesn't read files that are specified by directive sections. - for (MemoryBufferRef MB : Inputs) + for (MemoryBufferRef MB : MBs) Symtab.addFile(createFile(MB)); if (auto EC = Symtab.step()) { llvm::errs() << EC.message() << "\n"; return false; } + // Determine machine type and check if all object files are + // for the same CPU type. Note that this needs to be done before + // any call to mangle(). + for (std::unique_ptr &File : Symtab.getFiles()) { + MachineTypes MT = File->getMachineType(); + if (MT == IMAGE_FILE_MACHINE_UNKNOWN) + continue; + if (Config->MachineType == IMAGE_FILE_MACHINE_UNKNOWN) { + Config->MachineType = MT; + continue; + } + if (Config->MachineType != MT) { + llvm::errs() << File->getShortName() << ": machine type " + << machineTypeToStr(MT) << " conflicts with " + << machineTypeToStr(Config->MachineType) << "\n"; + return false; + } + } + if (Config->MachineType == IMAGE_FILE_MACHINE_UNKNOWN) { + llvm::errs() << "warning: /machine is not specified. x64 is assumed.\n"; + Config->MachineType = IMAGE_FILE_MACHINE_AMD64; + } + + // Windows specific -- Convert Windows resource files to a COFF file. + if (!Resources.empty()) { + auto MBOrErr = convertResToCOFF(Resources); + if (MBOrErr.getError()) + return false; + std::unique_ptr MB = std::move(MBOrErr.get()); + Symtab.addFile(createFile(MB->getMemBufferRef())); + OwningMBs.push_back(std::move(MB)); // take ownership + } + + if (!Entry.empty()) + Config->Entry = addUndefined(mangle(Entry)); + Symtab.addAbsolute(mangle("__ImageBase"), Config->ImageBase); + // Windows specific -- If entry point name is not given, we need to // infer that from user-defined entry name. - if (Config->Entry == nullptr && !Config->NoEntry) { + if (Entry.empty() && !Config->NoEntry) { StringRef S = findDefaultEntry(); if (S.empty()) { llvm::errs() << "entry point must be defined\n"; @@ -566,7 +598,7 @@ llvm::outs() << "Entry name inferred: " << S << "\n"; } - // Read as much files as we can. + // Read as much files as we can from directives sections. if (auto EC = Symtab.run()) { llvm::errs() << EC.message() << "\n"; return false; @@ -630,28 +662,6 @@ } } - // Check if all object files are for the same CPU type and - // compatible with /machine option (if given). - for (ObjectFile *File : Symtab.ObjectFiles) { - auto MT = static_cast(File->getCOFFObj()->getMachine()); - if (MT == IMAGE_FILE_MACHINE_UNKNOWN) - continue; - if (Config->MachineType == IMAGE_FILE_MACHINE_UNKNOWN) { - Config->MachineType = MT; - continue; - } - if (Config->MachineType != MT) { - llvm::errs() << File->getShortName() << ": machine type " - << machineTypeToStr(MT) << " conflicts with " - << machineTypeToStr(Config->MachineType) << "\n"; - return false; - } - } - if (Config->MachineType == IMAGE_FILE_MACHINE_UNKNOWN) { - llvm::errs() << "machine type must be specified\n"; - return false; - } - // Windows specific -- when we are creating a .dll file, we also // need to create a .lib file. if (!Config->Exports.empty()) Index: COFF/InputFiles.h =================================================================== --- COFF/InputFiles.h +++ COFF/InputFiles.h @@ -24,6 +24,8 @@ namespace coff { using llvm::LTOModule; +using llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN; +using llvm::COFF::MachineTypes; using llvm::object::Archive; using llvm::object::COFFObjectFile; using llvm::object::COFFSymbolRef; @@ -51,6 +53,9 @@ // file is broken. virtual std::error_code parse() = 0; + // Returns the CPU type this file was compiled to. + virtual MachineTypes getMachineType() { return IMAGE_FILE_MACHINE_UNKNOWN; } + // Returns a short, human-friendly filename. If this is a member of // an archive file, a returned value includes parent's filename. // Used for logging or debugging. @@ -112,6 +117,7 @@ explicit ObjectFile(MemoryBufferRef M) : InputFile(ObjectKind, M) {} static bool classof(const InputFile *F) { return F->kind() == ObjectKind; } std::error_code parse() override; + MachineTypes getMachineType() override; std::vector &getChunks() { return Chunks; } std::vector &getSymbols() override { return SymbolBodies; } @@ -181,6 +187,7 @@ explicit BitcodeFile(MemoryBufferRef M) : InputFile(BitcodeKind, M) {} static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; } std::vector &getSymbols() override { return SymbolBodies; } + MachineTypes getMachineType() override; LTOModule *getModule() const { return M.get(); } LTOModule *releaseModule() { return M.release(); } Index: COFF/InputFiles.cpp =================================================================== --- COFF/InputFiles.cpp +++ COFF/InputFiles.cpp @@ -24,8 +24,9 @@ using namespace llvm::object; using namespace llvm::support::endian; using llvm::RoundUpToAlignment; -using llvm::sys::fs::identify_magic; +using llvm::Triple; using llvm::sys::fs::file_magic; +using llvm::sys::fs::identify_magic; namespace lld { namespace coff { @@ -242,6 +243,12 @@ return B; } +MachineTypes ObjectFile::getMachineType() { + if (COFFObj) + return static_cast(COFFObj->getMachine()); + return IMAGE_FILE_MACHINE_UNKNOWN; +} + std::error_code ImportFile::parse() { const char *Buf = MB.getBufferStart(); const char *End = MB.getBufferEnd(); @@ -319,5 +326,20 @@ return std::error_code(); } +MachineTypes BitcodeFile::getMachineType() { + if (!M) + return IMAGE_FILE_MACHINE_UNKNOWN; + switch (Triple(M->getTargetTriple()).getArch()) { + case Triple::x86_64: + return IMAGE_FILE_MACHINE_AMD64; + case Triple::x86: + return IMAGE_FILE_MACHINE_I386; + case Triple::arm: + return IMAGE_FILE_MACHINE_ARMNT; + default: + return IMAGE_FILE_MACHINE_UNKNOWN; + } +} + } // namespace coff } // namespace lld Index: COFF/SymbolTable.h =================================================================== --- COFF/SymbolTable.h +++ COFF/SymbolTable.h @@ -42,6 +42,7 @@ class SymbolTable { public: void addFile(std::unique_ptr File); + std::vector> &getFiles() { return Files; } std::error_code step(); std::error_code run(); bool queueEmpty(); Index: COFF/Writer.cpp =================================================================== --- COFF/Writer.cpp +++ COFF/Writer.cpp @@ -592,7 +592,8 @@ // Dest is .reloc section. Add contents to that section. void Writer::addBaserels(OutputSection *Dest) { std::vector V; - Defined *ImageBase = cast(Symtab->find("__ImageBase")->Body); + StringRef Name = Config->is64() ? "__ImageBase" : "___ImageBase"; + Defined *ImageBase = cast(Symtab->find(Name)->Body); for (OutputSection *Sec : OutputSections) { if (Sec == Dest) continue; Index: test/COFF/Inputs/machine-x64.yaml =================================================================== --- /dev/null +++ test/COFF/Inputs/machine-x64.yaml @@ -0,0 +1,29 @@ +--- +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: 000000000000 +symbols: + - Name: .text + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 6 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: main + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... Index: test/COFF/Inputs/machine-x86.yaml =================================================================== --- /dev/null +++ test/COFF/Inputs/machine-x86.yaml @@ -0,0 +1,29 @@ +--- +header: + Machine: IMAGE_FILE_MACHINE_I386 + Characteristics: [] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: 000000000000 +symbols: + - Name: .text + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 6 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: _main + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... Index: test/COFF/hello32.test =================================================================== --- test/COFF/hello32.test +++ test/COFF/hello32.test @@ -1,6 +1,6 @@ # RUN: yaml2obj < %p/Inputs/hello32.yaml > %t.obj # RUN: lld -flavor link2 %t.obj %p/Inputs/std32.lib /subsystem:console \ -# RUN: /entry:_main@0 /out:%t.exe +# RUN: /entry:main@0 /out:%t.exe # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=HEADER %s # RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORTS %s Index: test/COFF/machine.test =================================================================== --- test/COFF/machine.test +++ test/COFF/machine.test @@ -1,61 +1,30 @@ -# RUN: sed -e s/MACHINETYPE/IMAGE_FILE_MACHINE_AMD64/ %s | yaml2obj > %t.obj +# RUN: yaml2obj %p/Inputs/machine-x64.yaml > %t.obj # RUN: lld -flavor link2 /entry:main /subsystem:console /out:%t.exe %t.obj # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=AMD64 %s # RUN: lld -flavor link2 /entry:main /subsystem:console /machine:x64 \ # RUN: /out:%t.exe %t.obj # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=AMD64 %s -# AMD64: Machine: IMAGE_FILE_MACHINE_AMD64 +AMD64: Machine: IMAGE_FILE_MACHINE_AMD64 -# RUN: sed -e s/MACHINETYPE/IMAGE_FILE_MACHINE_I386/ %s | yaml2obj > %t.obj +# RUN: yaml2obj %p/Inputs/machine-x86.yaml > %t.obj # RUN: lld -flavor link2 /entry:main /subsystem:console /out:%t.exe %t.obj # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=I386 %s # RUN: lld -flavor link2 /entry:main /subsystem:console /machine:x86 \ # RUN: /out:%t.exe %t.obj /fixed # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=I386 %s -# I386: Machine: IMAGE_FILE_MACHINE_I386 +I386: Machine: IMAGE_FILE_MACHINE_I386 -# RUN: sed -e s/MACHINETYPE/IMAGE_FILE_MACHINE_AMD64/ %s | yaml2obj > %t.obj +# RUN: yaml2obj %p/Inputs/machine-x64.yaml > %t.obj # RUN: not lld -flavor link2 /entry:main /subsystem:console /machine:x86 \ # RUN: /out:%t.exe %t.obj /fixed >& %t.log # RUN: FileCheck -check-prefix=INCOMPAT %s < %t.log -# RUN: sed -e s/MACHINETYPE/IMAGE_FILE_MACHINE_I386/ %s | yaml2obj > %t1.obj -# RUN: sed -e s/MACHINETYPE/IMAGE_FILE_MACHINE_AMD64/ %s | \ -# RUN: sed -e s/main/foo/ | yaml2obj > %t2.obj +# RUN: yaml2obj %p/Inputs/machine-x86.yaml > %t1.obj +# RUN: sed -e s/main/foo/ %p/Inputs/machine-x64.yaml | yaml2obj > %t2.obj # RUN: not lld -flavor link2 /entry:main /subsystem:console /out:%t.exe \ # RUN: %t1.obj %t2.obj >& %t.log # RUN: FileCheck -check-prefix=INCOMPAT %s < %t.log -# INCOMPAT: .obj: machine type x64 conflicts with x86 - ---- -header: - Machine: MACHINETYPE - Characteristics: [] -sections: - - Name: .text - Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] - Alignment: 4 - SectionData: 000000000000 -symbols: - - Name: .text - Value: 0 - SectionNumber: 1 - SimpleType: IMAGE_SYM_TYPE_NULL - ComplexType: IMAGE_SYM_DTYPE_NULL - StorageClass: IMAGE_SYM_CLASS_STATIC - SectionDefinition: - Length: 6 - NumberOfRelocations: 0 - NumberOfLinenumbers: 0 - CheckSum: 0 - Number: 0 - - Name: main - Value: 0 - SectionNumber: 1 - SimpleType: IMAGE_SYM_TYPE_NULL - ComplexType: IMAGE_SYM_DTYPE_NULL - StorageClass: IMAGE_SYM_CLASS_EXTERNAL -... +INCOMPAT: .obj: machine type x64 conflicts with x86 Index: test/COFF/reloc-x86.test =================================================================== --- test/COFF/reloc-x86.test +++ test/COFF/reloc-x86.test @@ -21,22 +21,22 @@ SectionData: A100000000A100000000A100000000A100000000A100000000A100000000 Relocations: - VirtualAddress: 1 - SymbolName: main + SymbolName: _main Type: IMAGE_REL_I386_ABSOLUTE - VirtualAddress: 6 - SymbolName: main + SymbolName: _main Type: IMAGE_REL_I386_DIR32 - VirtualAddress: 11 - SymbolName: main + SymbolName: _main Type: IMAGE_REL_I386_DIR32NB - VirtualAddress: 16 - SymbolName: main + SymbolName: _main Type: IMAGE_REL_I386_REL32 - VirtualAddress: 23 - SymbolName: main + SymbolName: _main Type: IMAGE_REL_I386_SECTION - VirtualAddress: 26 - SymbolName: main + SymbolName: _main Type: IMAGE_REL_I386_SECREL symbols: - Name: .text @@ -51,7 +51,7 @@ NumberOfLinenumbers: 0 CheckSum: 0 Number: 0 - - Name: main + - Name: _main Value: 0 SectionNumber: 1 SimpleType: IMAGE_SYM_TYPE_NULL