From 7c3e23fffd69307caa7973e1ac9053df9d0f01ed Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Thu, 9 Jul 2015 01:25:49 +0000 Subject: [PATCH] COFF: Fix import thunks and name mangling for x86. With this patch, LLD is now able to correctly link a "hello world" program written in assembly for 32-bit x86. llvm-svn: 241771 --- lld/COFF/Chunks.cpp | 4 +- lld/COFF/Driver.cpp | 19 ++++-- lld/COFF/Driver.h | 1 + lld/COFF/Writer.cpp | 5 +- lld/test/COFF/hello32.test | 118 +++++++++++++++++++++++++++++++++++ lld/test/COFF/imports32.test | 15 ----- lld/test/COFF/machine.test | 4 +- 7 files changed, 141 insertions(+), 25 deletions(-) create mode 100644 lld/test/COFF/hello32.test delete mode 100644 lld/test/COFF/imports32.test diff --git a/lld/COFF/Chunks.cpp b/lld/COFF/Chunks.cpp index a2164762a565..152e7c959b25 100644 --- a/lld/COFF/Chunks.cpp +++ b/lld/COFF/Chunks.cpp @@ -245,7 +245,9 @@ ImportThunkChunk::ImportThunkChunk(Defined *S) : ImpSymbol(S) { void ImportThunkChunk::writeTo(uint8_t *Buf) { memcpy(Buf + FileOff, ImportThunkData, sizeof(ImportThunkData)); // The first two bytes is a JMP instruction. Fill its operand. - uint32_t Operand = ImpSymbol->getRVA() - RVA - getSize(); + uint32_t Operand = Config->is64() + ? ImpSymbol->getRVA() - RVA - getSize() + : ImpSymbol->getRVA() + Config->ImageBase; write32le(Buf + FileOff + 2, Operand); } diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp index e582f348998e..522bc9bf0f9f 100644 --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -207,6 +207,13 @@ Undefined *LinkerDriver::addUndefined(StringRef Name) { return U; } +// Symbol names are mangled by appending "_" prefix on x86. +StringRef LinkerDriver::mangle(StringRef Sym) { + if (Config->MachineType == IMAGE_FILE_MACHINE_I386) + return Alloc.save("_" + Sym); + return Sym; +} + // Windows specific -- find default entry point name. StringRef LinkerDriver::findDefaultEntry() { // User-defined main functions and their corresponding entry points. @@ -217,9 +224,9 @@ StringRef LinkerDriver::findDefaultEntry() { {"wWinMain", "wWinMainCRTStartup"}, }; for (auto E : Entries) { - Symbol *Sym = Symtab.find(E[0]); + Symbol *Sym = Symtab.find(mangle(E[0])); if (Sym && !isa(Sym->Body)) - return E[1]; + return mangle(E[1]); } return ""; } @@ -227,9 +234,9 @@ StringRef LinkerDriver::findDefaultEntry() { WindowsSubsystem LinkerDriver::inferSubsystem() { if (Config->DLL) return IMAGE_SUBSYSTEM_WINDOWS_GUI; - if (Symtab.find("main") || Symtab.find("wmain")) + if (Symtab.find(mangle("main")) || Symtab.find(mangle("wmain"))) return IMAGE_SUBSYSTEM_WINDOWS_CUI; - if (Symtab.find("WinMain") || Symtab.find("wWinMain")) + if (Symtab.find(mangle("WinMain")) || Symtab.find(mangle("wWinMain"))) return IMAGE_SUBSYSTEM_WINDOWS_GUI; return IMAGE_SUBSYSTEM_UNKNOWN; } @@ -287,7 +294,7 @@ bool LinkerDriver::link(llvm::ArrayRef ArgsArr) { // Handle /entry if (auto *Arg = Args.getLastArg(OPT_entry)) - Config->Entry = addUndefined(Arg->getValue()); + Config->Entry = addUndefined(mangle(Arg->getValue())); // Handle /debug if (Args.hasArg(OPT_debug)) @@ -535,7 +542,7 @@ bool LinkerDriver::link(llvm::ArrayRef ArgsArr) { OwningMBs.push_back(std::move(MB)); // take ownership } - Symtab.addAbsolute("__ImageBase", Config->ImageBase); + 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. diff --git a/lld/COFF/Driver.h b/lld/COFF/Driver.h index 3cdfc06feb62..3cda42017d22 100644 --- a/lld/COFF/Driver.h +++ b/lld/COFF/Driver.h @@ -93,6 +93,7 @@ private: std::set VisitedFiles; Undefined *addUndefined(StringRef Sym); + StringRef mangle(StringRef Sym); // Windows specific -- "main" is not the only main function in Windows. // You can choose one from these four -- {w,}{WinMain,main}. diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp index bf3c0af67407..d8be9b15eddc 100644 --- a/lld/COFF/Writer.cpp +++ b/lld/COFF/Writer.cpp @@ -395,8 +395,11 @@ template void Writer::writeHeader() { COFF->Machine = Config->MachineType; COFF->NumberOfSections = OutputSections.size(); COFF->Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE; - if (Is64) + if (Is64) { COFF->Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE; + } else { + COFF->Characteristics |= IMAGE_FILE_32BIT_MACHINE; + } if (Config->DLL) COFF->Characteristics |= IMAGE_FILE_DLL; if (!Config->Relocatable) diff --git a/lld/test/COFF/hello32.test b/lld/test/COFF/hello32.test new file mode 100644 index 000000000000..a172e1c5d80c --- /dev/null +++ b/lld/test/COFF/hello32.test @@ -0,0 +1,118 @@ +# 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: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=HEADER %s +# RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORTS %s + +HEADER: Format: COFF-i386 +HEADER-NEXT: Arch: i386 +HEADER-NEXT: AddressSize: 32bit +HEADER-NEXT: ImageFileHeader { +HEADER-NEXT: Machine: IMAGE_FILE_MACHINE_I386 (0x14C) +HEADER-NEXT: SectionCount: 3 +HEADER-NEXT: TimeDateStamp: 1970-01-01 00:00:00 (0x0) +HEADER-NEXT: PointerToSymbolTable: 0x0 +HEADER-NEXT: SymbolCount: 0 +HEADER-NEXT: OptionalHeaderSize: 224 +HEADER-NEXT: Characteristics [ (0x102) +HEADER-NEXT: IMAGE_FILE_32BIT_MACHINE (0x100) +HEADER-NEXT: IMAGE_FILE_EXECUTABLE_IMAGE (0x2) +HEADER-NEXT: ] +HEADER-NEXT: } +HEADER-NEXT: ImageOptionalHeader { +HEADER-NEXT: MajorLinkerVersion: 0 +HEADER-NEXT: MinorLinkerVersion: 0 +HEADER-NEXT: SizeOfCode: 512 +HEADER-NEXT: SizeOfInitializedData: 1024 +HEADER-NEXT: SizeOfUninitializedData: 0 +HEADER-NEXT: AddressOfEntryPoint: 0x2000 +HEADER-NEXT: BaseOfCode: 0x2000 +HEADER-NEXT: BaseOfData: 0x0 +HEADER-NEXT: ImageBase: 0x40000000 +HEADER-NEXT: SectionAlignment: 4096 +HEADER-NEXT: FileAlignment: 512 +HEADER-NEXT: MajorOperatingSystemVersion: 6 +HEADER-NEXT: MinorOperatingSystemVersion: 0 +HEADER-NEXT: MajorImageVersion: 0 +HEADER-NEXT: MinorImageVersion: 0 +HEADER-NEXT: MajorSubsystemVersion: 6 +HEADER-NEXT: MinorSubsystemVersion: 0 +HEADER-NEXT: SizeOfImage: 16384 +HEADER-NEXT: SizeOfHeaders: 4096 +HEADER-NEXT: Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI (0x3) +HEADER-NEXT: Characteristics [ (0x8160) +HEADER-NEXT: IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE (0x40) +HEADER-NEXT: IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA (0x20) +HEADER-NEXT: IMAGE_DLL_CHARACTERISTICS_NX_COMPAT (0x100) +HEADER-NEXT: IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE (0x8000) +HEADER-NEXT: ] +HEADER-NEXT: SizeOfStackReserve: 1048576 +HEADER-NEXT: SizeOfStackCommit: 4096 +HEADER-NEXT: SizeOfHeapReserve: 1048576 +HEADER-NEXT: SizeOfHeapCommit: 4096 +HEADER-NEXT: NumberOfRvaAndSize: 16 +HEADER-NEXT: DataDirectory { +HEADER-NEXT: ExportTableRVA: 0x0 +HEADER-NEXT: ExportTableSize: 0x0 +HEADER-NEXT: ImportTableRVA: 0x3000 +HEADER-NEXT: ImportTableSize: 0x28 +HEADER-NEXT: ResourceTableRVA: 0x0 +HEADER-NEXT: ResourceTableSize: 0x0 +HEADER-NEXT: ExceptionTableRVA: 0x0 +HEADER-NEXT: ExceptionTableSize: 0x0 +HEADER-NEXT: CertificateTableRVA: 0x0 +HEADER-NEXT: CertificateTableSize: 0x0 +HEADER-NEXT: BaseRelocationTableRVA: 0x0 +HEADER-NEXT: BaseRelocationTableSize: 0x0 +HEADER-NEXT: DebugRVA: 0x0 +HEADER-NEXT: DebugSize: 0x0 +HEADER-NEXT: ArchitectureRVA: 0x0 +HEADER-NEXT: ArchitectureSize: 0x0 +HEADER-NEXT: GlobalPtrRVA: 0x0 +HEADER-NEXT: GlobalPtrSize: 0x0 +HEADER-NEXT: TLSTableRVA: 0x0 +HEADER-NEXT: TLSTableSize: 0x0 +HEADER-NEXT: LoadConfigTableRVA: 0x0 +HEADER-NEXT: LoadConfigTableSize: 0x0 +HEADER-NEXT: BoundImportRVA: 0x0 +HEADER-NEXT: BoundImportSize: 0x0 +HEADER-NEXT: IATRVA: 0x3034 +HEADER-NEXT: IATSize: 0xC +HEADER-NEXT: DelayImportDescriptorRVA: 0x0 +HEADER-NEXT: DelayImportDescriptorSize: 0x0 +HEADER-NEXT: CLRRuntimeHeaderRVA: 0x0 +HEADER-NEXT: CLRRuntimeHeaderSize: 0x0 +HEADER-NEXT: ReservedRVA: 0x0 +HEADER-NEXT: ReservedSize: 0x0 +HEADER-NEXT: } +HEADER-NEXT: } +HEADER-NEXT: DOSHeader { +HEADER-NEXT: Magic: MZ +HEADER-NEXT: UsedBytesInTheLastPage: 0 +HEADER-NEXT: FileSizeInPages: 0 +HEADER-NEXT: NumberOfRelocationItems: 0 +HEADER-NEXT: HeaderSizeInParagraphs: 0 +HEADER-NEXT: MinimumExtraParagraphs: 0 +HEADER-NEXT: MaximumExtraParagraphs: 0 +HEADER-NEXT: InitialRelativeSS: 0 +HEADER-NEXT: InitialSP: 0 +HEADER-NEXT: Checksum: 0 +HEADER-NEXT: InitialIP: 0 +HEADER-NEXT: InitialRelativeCS: 0 +HEADER-NEXT: AddressOfRelocationTable: 64 +HEADER-NEXT: OverlayNumber: 0 +HEADER-NEXT: OEMid: 0 +HEADER-NEXT: OEMinfo: 0 +HEADER-NEXT: AddressOfNewExeHeader: 64 +HEADER-NEXT: } + +IMPORTS: Format: COFF-i386 +IMPORTS: Arch: i386 +IMPORTS: AddressSize: 32bit +IMPORTS: Import { +IMPORTS: Name: std32.dll +IMPORTS: ImportLookupTableRVA: 0x3028 +IMPORTS: ImportAddressTableRVA: 0x3034 +IMPORTS: Symbol: ExitProcess (0) +IMPORTS: Symbol: MessageBoxA (1) +IMPORTS: } diff --git a/lld/test/COFF/imports32.test b/lld/test/COFF/imports32.test deleted file mode 100644 index 878b583e5722..000000000000 --- a/lld/test/COFF/imports32.test +++ /dev/null @@ -1,15 +0,0 @@ -# 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: llvm-readobj -coff-imports %t.exe | FileCheck %s - -CHECK: Format: COFF-i386 -CHECK: Arch: i386 -CHECK: AddressSize: 32bit -CHECK: Import { -CHECK: Name: std32.dll -CHECK: ImportLookupTableRVA: 0x3028 -CHECK: ImportAddressTableRVA: 0x3034 -CHECK: Symbol: ExitProcess (0) -CHECK: Symbol: MessageBoxA (1) -CHECK: } diff --git a/lld/test/COFF/machine.test b/lld/test/COFF/machine.test index 7a72ad831abb..8b1d6a3886c5 100644 --- a/lld/test/COFF/machine.test +++ b/lld/test/COFF/machine.test @@ -11,14 +11,14 @@ # 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 +# 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 # RUN: sed -e s/MACHINETYPE/IMAGE_FILE_MACHINE_AMD64/ %s | yaml2obj > %t.obj # RUN: not lld -flavor link2 /entry:main /subsystem:console /machine:x86 \ -# RUN: /out:%t.exe %t.obj >& %t.log +# 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