diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -89,7 +89,7 @@ // and such fields have the same name as the corresponding options. // Most fields are initialized by the driver. struct Configuration { - uint8_t osabi = 0; + llvm::Optional osabi; uint32_t andFeatures = 0; llvm::CachePruningPolicy thinLTOCachePolicy; llvm::SetVector dependencyFiles; // for --dependency-file diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -134,8 +134,9 @@ } // Parses a linker -m option. -static std::tuple parseEmulation(StringRef emul) { - uint8_t osabi = 0; +static std::tuple> +parseEmulation(StringRef emul) { + Optional osabi; StringRef s = emul; if (s.endswith("_fbsd")) { s = s.drop_back(5); @@ -1465,16 +1466,19 @@ // If -m was not given, infer it from object files. void LinkerDriver::inferMachineType() { - if (config->ekind != ELFNoneKind) + if (config->ekind != ELFNoneKind && config->osabi) return; for (InputFile *f : files) { if (f->ekind == ELFNoneKind) continue; - config->ekind = f->ekind; - config->emachine = f->emachine; - config->osabi = f->osabi; - config->mipsN32Abi = config->emachine == EM_MIPS && isMipsN32Abi(f); + if (config->ekind == ELFNoneKind) { + config->ekind = f->ekind; + config->emachine = f->emachine; + config->mipsN32Abi = config->emachine == EM_MIPS && isMipsN32Abi(f); + } + if (!config->osabi) + config->osabi = f->osabi; return; } error("target emulation unknown: -m or at least one .o file required"); diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -3709,7 +3709,7 @@ eHdr->e_ident[EI_CLASS] = config->is64 ? ELFCLASS64 : ELFCLASS32; eHdr->e_ident[EI_DATA] = config->isLE ? ELFDATA2LSB : ELFDATA2MSB; eHdr->e_ident[EI_VERSION] = EV_CURRENT; - eHdr->e_ident[EI_OSABI] = config->osabi; + eHdr->e_ident[EI_OSABI] = *config->osabi; eHdr->e_ident[EI_ABIVERSION] = getAbiVersion(); eHdr->e_machine = config->emachine; eHdr->e_version = EV_CURRENT; diff --git a/lld/test/ELF/basic-freebsd.s b/lld/test/ELF/basic-freebsd.s --- a/lld/test/ELF/basic-freebsd.s +++ b/lld/test/ELF/basic-freebsd.s @@ -2,8 +2,16 @@ # Verify that OSABI is set to the correct value. # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-freebsd %s -o %t +# RUN: llvm-readobj --file-headers %t | FileCheck %s --check-prefixes CHECK,CHECK-OBJ # RUN: ld.lld %t -o %t2 -# RUN: llvm-readobj --file-headers %t2 | FileCheck %s +# RUN: llvm-readobj --file-headers %t2 | FileCheck %s --check-prefixes CHECK,CHECK-EXE +# An explicit _fbsd emulation should set the FreeBSD OSABI +# RUN: ld.lld -m elf_x86_64_fbsd %t -o %t2 +# RUN: llvm-readobj --file-headers %t2 | FileCheck %s --check-prefixes CHECK,CHECK-EXE +# If the emulation does not encode a specific OSABI, we should infer +# it from the first input .o file rather than using SysV. +# RUN: ld.lld -m elf_x86_64 %t -o %t2 +# RUN: llvm-readobj --file-headers %t2 | FileCheck %s --check-prefixes CHECK,CHECK-EXE .globl _start _start: @@ -21,5 +29,6 @@ # CHECK-NEXT: ABIVersion: 0 # CHECK-NEXT: Unused: (00 00 00 00 00 00 00) # CHECK-NEXT: } -# CHECK-NEXT: Type: Executable (0x2) -# CHECK-NEXT: Machine: EM_X86_64 (0x3E) +# CHECK-OBJ-NEXT: Type: Relocatable (0x1) +# CHECK-EXE-NEXT: Type: Executable (0x2) +# CHECK-NEXT: Machine: EM_X86_64 (0x3E)