diff --git a/lib/Readers/BinaryFileParser.cpp b/lib/Readers/BinaryFileParser.cpp index 9f51e1440..169026c05 100644 --- a/lib/Readers/BinaryFileParser.cpp +++ b/lib/Readers/BinaryFileParser.cpp @@ -25,6 +25,9 @@ eld::Expected BinaryFileParser::parseFile(InputFile &inputFile) { ObjectFile *objFile = llvm::cast(&inputFile); objFile->addSection(S); addDescriptionSymbols(inputFile, S); + // Binary files carry no architecture flags. Explicitly set flags to 0. + if (m_Module.getLinker()->getBackend()) + m_Module.getBackend().getInfo().checkFlags(0, &inputFile, false); return {}; } diff --git a/lib/Target/ARM/ARMInfo.cpp b/lib/Target/ARM/ARMInfo.cpp index 0f6adf29d..506fe8af7 100644 --- a/lib/Target/ARM/ARMInfo.cpp +++ b/lib/Target/ARM/ARMInfo.cpp @@ -66,3 +66,21 @@ bool ARMInfo::InitializeDefaultMappings(Module &pModule) { } std::string ARMInfo::flagString(uint64_t flag) const { return "arm"; } + +uint64_t ARMInfo::flags() const { + // checkFlags() was never called. This means the linker was given a lone empty + // .o file or a lone symdef file, etc. In either case, we want the result to + // have flags. + if (!OutputFlags) + return llvm::ELF::EF_ARM_EABI_VER5; + assert(*OutputFlags == 0 || *OutputFlags == llvm::ELF::EF_ARM_EABI_VER5); + return *OutputFlags; +} + +bool ARMInfo::checkFlags(uint64_t Flags, const InputFile *I, bool) const { + if (!OutputFlags && Flags == 0 && I->isBinaryFile()) + OutputFlags = Flags; + else + OutputFlags = llvm::ELF::EF_ARM_EABI_VER5; + return true; +} \ No newline at end of file diff --git a/lib/Target/ARM/ARMInfo.h b/lib/Target/ARM/ARMInfo.h index c9c62c145..a3d90e145 100644 --- a/lib/Target/ARM/ARMInfo.h +++ b/lib/Target/ARM/ARMInfo.h @@ -37,7 +37,7 @@ class ARMInfo : public TargetInfo { : 0x4; } - uint64_t flags() const override { return llvm::ELF::EF_ARM_EABI_VER5; } + uint64_t flags() const override; uint64_t startAddr(bool linkerScriptHasSectionsCommand, bool isDynExec, bool loadPhdr) const override { @@ -81,6 +81,11 @@ class ARMInfo : public TargetInfo { m_Config.options().setWarnMismatch(false); } } + + bool checkFlags(uint64_t Flag, const InputFile *I, bool) const override; + +private: + mutable std::optional OutputFlags; }; } // namespace eld diff --git a/lib/Target/Hexagon/HexagonInfo.cpp b/lib/Target/Hexagon/HexagonInfo.cpp index 3f52bf86e..c4d3a99b0 100644 --- a/lib/Target/Hexagon/HexagonInfo.cpp +++ b/lib/Target/Hexagon/HexagonInfo.cpp @@ -108,8 +108,6 @@ bool HexagonInfo::initialize() { return false; } - m_OutputFlag = m_CmdLineFlag; - return true; } @@ -255,8 +253,14 @@ HexagonInfo::ArchSupport HexagonInfo::getArchSupport(uint64_t pFlag) const { bool HexagonInfo::checkFlags(uint64_t pFlag, const InputFile *pInputFile, bool) const { - if (!pFlag) + if (!pFlag) { + if (pInputFile->isBinaryFile()) + ZeroFlagsOK = true; return true; + } + + if (m_CmdLineFlag != LINK_UNKNOWN) + m_OutputFlag = m_CmdLineFlag; HexagonInfo::ArchSupport archSupport = getArchSupport(pFlag); @@ -310,6 +314,8 @@ bool HexagonInfo::checkFlags(uint64_t pFlag, const InputFile *pInputFile, /// flags - the value of ElfXX_Ehdr::e_flags uint64_t HexagonInfo::flags() const { + if (m_OutputFlag == LINK_UNKNOWN && ZeroFlagsOK) + return 0; int32_t OutputFlag = m_OutputFlag; if (m_CmdLineFlag != LINK_UNKNOWN) { if (OutputFlag == LINK_UNKNOWN) diff --git a/lib/Target/Hexagon/HexagonInfo.h b/lib/Target/Hexagon/HexagonInfo.h index 43bd6ec61..094b34391 100644 --- a/lib/Target/Hexagon/HexagonInfo.h +++ b/lib/Target/Hexagon/HexagonInfo.h @@ -88,6 +88,7 @@ class HexagonInfo : public TargetInfo { private: int32_t m_CmdLineFlag; mutable int32_t m_OutputFlag; + mutable bool ZeroFlagsOK = false; }; } // namespace eld diff --git a/lib/Target/RISCV/RISCVInfo.cpp b/lib/Target/RISCV/RISCVInfo.cpp index 5302b7591..2da1ec2e4 100644 --- a/lib/Target/RISCV/RISCVInfo.cpp +++ b/lib/Target/RISCV/RISCVInfo.cpp @@ -11,8 +11,6 @@ using namespace eld; -#define UNKNOWN -1 - std::string RISCVInfo::flagString(uint64_t flag) const { #define INTOEFLAGSTR(ns, enum, str) \ if ((flag & ns::enum) == ns::enum) { \ @@ -36,9 +34,7 @@ llvm::StringRef RISCVInfo::getOutputMCPU() const { //===----------------------------------------------------------------------===// // RISCVInfo //===----------------------------------------------------------------------===// -RISCVInfo::RISCVInfo(LinkerConfig &pConfig) : TargetInfo(pConfig) { - m_OutputFlag = UNKNOWN; -} +RISCVInfo::RISCVInfo(LinkerConfig &pConfig) : TargetInfo(pConfig) {} uint64_t RISCVInfo::translateFlag(uint64_t pFlag) const { return pFlag; } @@ -49,34 +45,35 @@ bool RISCVInfo::isABIFlagSet(uint64_t inputFlag, uint32_t ABIFlag) const { } bool RISCVInfo::isCompatible(uint64_t pFlag, const std::string &pFile) const { + assert(m_OutputFlag); if (isABIFlagSet(pFlag, llvm::ELF::EF_RISCV_FLOAT_ABI_SOFT) ^ - isABIFlagSet(m_OutputFlag, llvm::ELF::EF_RISCV_FLOAT_ABI_SOFT)) { + isABIFlagSet(*m_OutputFlag, llvm::ELF::EF_RISCV_FLOAT_ABI_SOFT)) { m_Config.raise(Diag::incompatible_architecture_versions) - << flagString(pFlag) << pFile << flagString(m_OutputFlag); + << flagString(pFlag) << pFile << flagString(*m_OutputFlag); return false; } if (isABIFlagSet(pFlag, llvm::ELF::EF_RISCV_FLOAT_ABI_SINGLE) ^ - isABIFlagSet(m_OutputFlag, llvm::ELF::EF_RISCV_FLOAT_ABI_SINGLE)) { + isABIFlagSet(*m_OutputFlag, llvm::ELF::EF_RISCV_FLOAT_ABI_SINGLE)) { m_Config.raise(Diag::incompatible_architecture_versions) - << flagString(pFlag) << pFile << flagString(m_OutputFlag); + << flagString(pFlag) << pFile << flagString(*m_OutputFlag); return false; } if (isABIFlagSet(pFlag, llvm::ELF::EF_RISCV_FLOAT_ABI_DOUBLE) ^ - isABIFlagSet(m_OutputFlag, llvm::ELF::EF_RISCV_FLOAT_ABI_DOUBLE)) { + isABIFlagSet(*m_OutputFlag, llvm::ELF::EF_RISCV_FLOAT_ABI_DOUBLE)) { m_Config.raise(Diag::incompatible_architecture_versions) - << flagString(pFlag) << pFile << flagString(m_OutputFlag); + << flagString(pFlag) << pFile << flagString(*m_OutputFlag); return false; } if (isABIFlagSet(pFlag, llvm::ELF::EF_RISCV_FLOAT_ABI_QUAD) ^ - isABIFlagSet(m_OutputFlag, llvm::ELF::EF_RISCV_FLOAT_ABI_QUAD)) { + isABIFlagSet(*m_OutputFlag, llvm::ELF::EF_RISCV_FLOAT_ABI_QUAD)) { m_Config.raise(Diag::incompatible_architecture_versions) - << flagString(pFlag) << pFile << flagString(m_OutputFlag); + << flagString(pFlag) << pFile << flagString(*m_OutputFlag); return false; } if ((pFlag & llvm::ELF::EF_RISCV_RVE) ^ - (m_OutputFlag & llvm::ELF::EF_RISCV_RVE)) { + (*m_OutputFlag & llvm::ELF::EF_RISCV_RVE)) { m_Config.raise(Diag::incompatible_architecture_versions) - << flagString(pFlag) << pFile << flagString(m_OutputFlag); + << flagString(pFlag) << pFile << flagString(*m_OutputFlag); return false; } return true; @@ -85,28 +82,23 @@ bool RISCVInfo::isCompatible(uint64_t pFlag, const std::string &pFile) const { bool RISCVInfo::checkFlags(uint64_t flag, const InputFile *pInputFile, bool hasExecutableSections) const { // If flag is empty and no executable sections found in the ELF file - // skip checking for compatibility + // skip checking for compatibility. if (!flag && !hasExecutableSections) return true; - // Choose the default architecture from the input files, only if mcpu option - // is not specified on the command line. - if (m_OutputFlag == UNKNOWN) + if (!m_OutputFlag) m_OutputFlag = flag; if (!isCompatible(flag, pInputFile->getInput()->decoratedPath())) return false; - m_OutputFlag |= flag; + *m_OutputFlag |= flag; InputFlags[pInputFile] = flag; return true; } -/// flags - the value of ElfXX_Ehdr::e_flags -uint64_t RISCVInfo::flags() const { return m_OutputFlag; } - uint8_t RISCVInfo::OSABI() const { return llvm::ELF::ELFOSABI_NONE; } bool RISCVInfo::InitializeDefaultMappings(Module &pModule) { diff --git a/lib/Target/RISCV/RISCVInfo.h b/lib/Target/RISCV/RISCVInfo.h index 957eabd27..7e3003ff7 100644 --- a/lib/Target/RISCV/RISCVInfo.h +++ b/lib/Target/RISCV/RISCVInfo.h @@ -22,7 +22,7 @@ class RISCVInfo : public TargetInfo { std::string getMachineStr() const override { return "RISC-V"; } /// flags - the value of ElfXX_Ehdr::e_flags - uint64_t flags() const override; + uint64_t flags() const override { return m_OutputFlag ? *m_OutputFlag : 0; } uint8_t OSABI() const override; @@ -53,7 +53,7 @@ class RISCVInfo : public TargetInfo { private: uint64_t translateFlag(uint64_t pFlag) const; - mutable int64_t m_OutputFlag; + mutable std::optional m_OutputFlag; mutable llvm::DenseMap InputFlags; }; diff --git a/test/ARM/standalone/EFlags/Inputs/1.c b/test/ARM/standalone/EFlags/Inputs/1.c new file mode 100644 index 000000000..caf871927 --- /dev/null +++ b/test/ARM/standalone/EFlags/Inputs/1.c @@ -0,0 +1 @@ +int foo() {return 0;} \ No newline at end of file diff --git a/test/ARM/standalone/EFlags/Inputs/binary.test b/test/ARM/standalone/EFlags/Inputs/binary.test new file mode 100644 index 000000000..e32c42824 --- /dev/null +++ b/test/ARM/standalone/EFlags/Inputs/binary.test @@ -0,0 +1,11 @@ +#---binary.test--------------------- Executable---------------------# +#BEGIN_COMMENT +# Checks output flags are set when there is a binary input +# combined with an object input. +#END_COMMENT +#START_TEST +RUN: %link %emulation %linkopts --format=binary %s -o %t.out +RUN: %readelf -h %t.out | %filecheck %s +#END_TEST + +CHECK: Flags: 0x0 \ No newline at end of file diff --git a/test/ARM/standalone/EFlags/binaryflags.test b/test/ARM/standalone/EFlags/binaryflags.test new file mode 100644 index 000000000..14b3aa9e5 --- /dev/null +++ b/test/ARM/standalone/EFlags/binaryflags.test @@ -0,0 +1,12 @@ +#---binaryflags.test--------------------- Executable---------------------# +#BEGIN_COMMENT +# Checks output flags are set for a link that has a binary file +# and object file. +#END_COMMENT +#START_TEST +RUN: %clang -c %clangopts %p/Inputs/1.c -o %t.o +RUN: %link %emulation %linkopts %t.o --format=binary %s -o %t.out +RUN: %readelf -h %t.out | %filecheck %s +#END_TEST + +CHECK: Flags: 0x5000000 \ No newline at end of file diff --git a/test/Common/standalone/BinaryFormatInputFiles/flags.test b/test/Common/standalone/BinaryFormatInputFiles/flags.test new file mode 100644 index 000000000..7bc7b955d --- /dev/null +++ b/test/Common/standalone/BinaryFormatInputFiles/flags.test @@ -0,0 +1,10 @@ +#---flags.test--------------------- Executable---------------------# +#BEGIN_COMMENT +# Checks output flags are 0 for binary inputs +#END_COMMENT +#START_TEST +RUN: %link %emulation %linkopts --format=binary %s -o %t.out +RUN: %readelf -h %t.out | %filecheck %s +#END_TEST + +CHECK: Flags: 0x0 \ No newline at end of file diff --git a/test/Hexagon/standalone/EFlags/Inputs/1.c b/test/Hexagon/standalone/EFlags/Inputs/1.c new file mode 100644 index 000000000..caf871927 --- /dev/null +++ b/test/Hexagon/standalone/EFlags/Inputs/1.c @@ -0,0 +1 @@ +int foo() {return 0;} \ No newline at end of file diff --git a/test/Hexagon/standalone/EFlags/binaryflags.test b/test/Hexagon/standalone/EFlags/binaryflags.test new file mode 100644 index 000000000..5d1548041 --- /dev/null +++ b/test/Hexagon/standalone/EFlags/binaryflags.test @@ -0,0 +1,12 @@ +#---binaryflags.test--------------------- Executable---------------------# +#BEGIN_COMMENT +# Checks output flags are set for a link that has a binary file +# and object file. +#END_COMMENT +#START_TEST +RUN: %clang -c %clangopts %p/Inputs/1.c -o %t.o +RUN: %link -mv75 %linkopts %t.o --format=binary %s -o %t.out +RUN: %readelf -h %t.out | %filecheck %s +#END_TEST + +CHECK: Flags: 0x75 \ No newline at end of file diff --git a/test/Hexagon/standalone/Elfcopy/ObjCopyBinary/Inputs/txtfile b/test/Hexagon/standalone/Elfcopy/ObjCopyBinary/Inputs/txtfile deleted file mode 100644 index 257cc5642..000000000 --- a/test/Hexagon/standalone/Elfcopy/ObjCopyBinary/Inputs/txtfile +++ /dev/null @@ -1 +0,0 @@ -foo diff --git a/test/Hexagon/standalone/Elfcopy/ObjCopyBinary/ObjCopyBinary.test b/test/Hexagon/standalone/Elfcopy/ObjCopyBinary/ObjCopyBinary.test deleted file mode 100644 index 03a956815..000000000 --- a/test/Hexagon/standalone/Elfcopy/ObjCopyBinary/ObjCopyBinary.test +++ /dev/null @@ -1,11 +0,0 @@ -#---ObjCopyBinary.test--------------------- Exe------------------# -#BEGIN_COMMENT -#When users use objcopy to create binary files, the ELF file returned by objcopy -#doesnot have any flags set. It would be useful to support the usecase since -#objcopy doesnot know what flag needs to be set. -#END_COMMENT -RUN: %elfcopy -I binary -O elf32-hexagon %p/Inputs/txtfile %t1.1.o -RUN: %link %t1.1.o -o %t2.out -RUN: %readelf -h %t2.out | %filecheck %s -check-prefix=FLAGS - -#FLAGS: 0x68