Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[llvm-lib][Object] Add support for EC importlib symbols. #81059

Merged
merged 1 commit into from
Feb 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions llvm/include/llvm/Object/COFF.h
Original file line number Diff line number Diff line change
Expand Up @@ -1362,6 +1362,47 @@ class SectionStrippedError
SectionStrippedError() { setErrorCode(object_error::section_stripped); }
};

inline std::optional<std::string>
getArm64ECMangledFunctionName(StringRef Name) {
dpaoliello marked this conversation as resolved.
Show resolved Hide resolved
bool IsCppFn = Name[0] == '?';
if (IsCppFn && Name.find("$$h") != std::string::npos)
return std::nullopt;
if (!IsCppFn && Name[0] == '#')
return std::nullopt;

StringRef Prefix = "$$h";
size_t InsertIdx = 0;
if (IsCppFn) {
InsertIdx = Name.find("@@");
size_t ThreeAtSignsIdx = Name.find("@@@");
if (InsertIdx != std::string::npos && InsertIdx != ThreeAtSignsIdx) {
InsertIdx += 2;
} else {
InsertIdx = Name.find("@");
if (InsertIdx != std::string::npos)
InsertIdx++;
}
} else {
Prefix = "#";
}

return std::optional<std::string>(
(Name.substr(0, InsertIdx) + Prefix + Name.substr(InsertIdx)).str());
}

inline std::optional<std::string>
getArm64ECDemangledFunctionName(StringRef Name) {
if (Name[0] == '#')
return std::string(Name.substr(1));
if (Name[0] != '?')
return std::nullopt;

std::pair<StringRef, StringRef> Pair = Name.split("$$h");
if (Pair.second.empty())
return std::nullopt;
return (Pair.first + Pair.second).str();
}

} // end namespace object

} // end namespace llvm
Expand Down
28 changes: 25 additions & 3 deletions llvm/include/llvm/Object/COFFImportFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ namespace llvm {
namespace object {

class COFFImportFile : public SymbolicFile {
private:
enum SymbolIndex { ImpSymbol, ThunkSymbol, ECAuxSymbol, ECThunkSymbol };

public:
COFFImportFile(MemoryBufferRef Source)
: SymbolicFile(ID_COFFImportFile, Source) {}
Expand All @@ -36,9 +39,23 @@ class COFFImportFile : public SymbolicFile {
void moveSymbolNext(DataRefImpl &Symb) const override { ++Symb.p; }

Error printSymbolName(raw_ostream &OS, DataRefImpl Symb) const override {
if (Symb.p == 0)
switch (Symb.p) {
case ImpSymbol:
OS << "__imp_";
OS << StringRef(Data.getBufferStart() + sizeof(coff_import_header));
break;
case ECAuxSymbol:
OS << "__imp_aux_";
break;
}
const char *Name = Data.getBufferStart() + sizeof(coff_import_header);
if (Symb.p != ECThunkSymbol && COFF::isArm64EC(getMachine())) {
if (std::optional<std::string> DemangledName =
getArm64ECDemangledFunctionName(Name)) {
OS << StringRef(*DemangledName);
return Error::success();
}
}
OS << StringRef(Name);
return Error::success();
}

Expand All @@ -52,7 +69,12 @@ class COFFImportFile : public SymbolicFile {

basic_symbol_iterator symbol_end() const override {
DataRefImpl Symb;
Symb.p = isData() ? 1 : 2;
if (isData())
Symb.p = ImpSymbol + 1;
else if (COFF::isArm64EC(getMachine()))
Symb.p = ECThunkSymbol + 1;
else
Symb.p = ThunkSymbol + 1;
return BasicSymbolRef(Symb, this);
}

Expand Down
15 changes: 15 additions & 0 deletions llvm/lib/Object/COFFImportFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -684,6 +684,21 @@ Error writeImportLibrary(StringRef ImportName, StringRef Path,
NameType = getNameType(SymbolName, E.Name, Machine, MinGW);
}

// On ARM64EC, use EXPORTAS to import demangled name for mangled symbols.
if (ImportType == IMPORT_CODE && isArm64EC(Machine)) {
if (std::optional<std::string> MangledName =
getArm64ECMangledFunctionName(Name)) {
if (ExportName.empty()) {
NameType = IMPORT_NAME_EXPORTAS;
ExportName.swap(Name);
}
Name = std::move(*MangledName);
} else if (ExportName.empty()) {
NameType = IMPORT_NAME_EXPORTAS;
ExportName = std::move(*getArm64ECDemangledFunctionName(Name));
}
}

Members.push_back(OF.createShortImport(Name, E.Ordinal, ImportType,
NameType, ExportName, Machine));
}
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Target/AArch64/AArch64Arm64ECCallLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,13 @@
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instruction.h"
#include "llvm/InitializePasses.h"
#include "llvm/Object/COFF.h"
#include "llvm/Pass.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/TargetParser/Triple.h"

using namespace llvm;
using namespace llvm::object;

using OperandBundleDef = OperandBundleDefT<Value *>;

Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Target/AArch64/AArch64MCInstLower.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/Object/COFF.h"
#include "llvm/Support/CodeGen.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Target/TargetLoweringObjectFile.h"
#include "llvm/Target/TargetMachine.h"
using namespace llvm;
using namespace llvm::object;

extern cl::opt<bool> EnableAArch64ELFLocalDynamicTLSGeneration;

Expand Down
28 changes: 0 additions & 28 deletions llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -248,34 +248,6 @@ static inline bool atomicBarrierDroppedOnZero(unsigned Opcode) {
return false;
}

static inline std::optional<std::string>
getArm64ECMangledFunctionName(std::string Name) {
bool IsCppFn = Name[0] == '?';
if (IsCppFn && Name.find("$$h") != std::string::npos)
return std::nullopt;
if (!IsCppFn && Name[0] == '#')
return std::nullopt;

StringRef Prefix = "$$h";
size_t InsertIdx = 0;
if (IsCppFn) {
InsertIdx = Name.find("@@");
size_t ThreeAtSignsIdx = Name.find("@@@");
if (InsertIdx != std::string::npos && InsertIdx != ThreeAtSignsIdx) {
InsertIdx += 2;
} else {
InsertIdx = Name.find("@");
if (InsertIdx != std::string::npos)
InsertIdx++;
}
} else {
Prefix = "#";
}

Name.insert(Name.begin() + InsertIdx, Prefix.begin(), Prefix.end());
return std::optional<std::string>(Name);
}

namespace AArch64CC {

// The CondCodes constants map directly to the 4-bit encoding of the condition
Expand Down
141 changes: 140 additions & 1 deletion llvm/test/tools/llvm-lib/arm64ec-implib.test
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,23 @@ ARMAP-NEXT: __NULL_IMPORT_DESCRIPTOR in test.dll
ARMAP-NEXT: test_NULL_THUNK_DATA in test.dll
ARMAP-EMPTY:
ARMAP-NEXT: Archive EC map
ARMAP-NEXT: #expname in test.dll
ARMAP-NEXT: #funcexp in test.dll
ARMAP-NEXT: #mangledfunc in test.dll
ARMAP-NEXT: ?test_cpp_func@@$$hYAHPEAX@Z in test.dll
ARMAP-NEXT: ?test_cpp_func@@YAHPEAX@Z in test.dll
ARMAP-NEXT: __imp_?test_cpp_func@@YAHPEAX@Z in test.dll
ARMAP-NEXT: __imp_aux_?test_cpp_func@@YAHPEAX@Z in test.dll
ARMAP-NEXT: __imp_aux_expname in test.dll
ARMAP-NEXT: __imp_aux_funcexp in test.dll
ARMAP-NEXT: __imp_aux_mangledfunc in test.dll
ARMAP-NEXT: __imp_dataexp in test.dll
ARMAP-NEXT: __imp_expname in test.dll
ARMAP-NEXT: __imp_funcexp in test.dll
ARMAP-NEXT: __imp_mangledfunc in test.dll
ARMAP-NEXT: expname in test.dll
ARMAP-NEXT: funcexp in test.dll
ARMAP-NEXT: mangledfunc in test.dll

RUN: llvm-readobj test.lib | FileCheck -check-prefix=READOBJ %s

Expand All @@ -35,10 +49,42 @@ READOBJ-EMPTY:
READOBJ-NEXT: File: test.dll
READOBJ-NEXT: Format: COFF-import-file-ARM64EC
READOBJ-NEXT: Type: code
READOBJ-NEXT: Name type: name
READOBJ-NEXT: Name type: export as
READOBJ-NEXT: Export name: funcexp
READOBJ-NEXT: Symbol: __imp_funcexp
READOBJ-NEXT: Symbol: funcexp
READOBJ-NEXT: Symbol: __imp_aux_funcexp
READOBJ-NEXT: Symbol: #funcexp
READOBJ-EMPTY:
READOBJ-NEXT: File: test.dll
READOBJ-NEXT: Format: COFF-import-file-ARM64EC
READOBJ-NEXT: Type: code
READOBJ-NEXT: Name type: export as
READOBJ-NEXT: Export name: mangledfunc
READOBJ-NEXT: Symbol: __imp_mangledfunc
READOBJ-NEXT: Symbol: mangledfunc
READOBJ-NEXT: Symbol: __imp_aux_mangledfunc
READOBJ-NEXT: Symbol: #mangledfunc
READOBJ-EMPTY:
READOBJ-NEXT: File: test.dll
READOBJ-NEXT: Format: COFF-import-file-ARM64EC
READOBJ-NEXT: Type: code
READOBJ-NEXT: Name type: export as
READOBJ-NEXT: Export name: ?test_cpp_func@@YAHPEAX@Z
READOBJ-NEXT: Symbol: __imp_?test_cpp_func@@YAHPEAX@Z
READOBJ-NEXT: Symbol: ?test_cpp_func@@YAHPEAX@Z
READOBJ-NEXT: Symbol: __imp_aux_?test_cpp_func@@YAHPEAX@Z
READOBJ-NEXT: Symbol: ?test_cpp_func@@$$hYAHPEAX@Z
READOBJ-EMPTY:
READOBJ-NEXT: File: test.dll
READOBJ-NEXT: Format: COFF-import-file-ARM64EC
READOBJ-NEXT: Type: code
READOBJ-NEXT: Name type: export as
READOBJ-NEXT: Export name: expname
READOBJ-NEXT: Symbol: __imp_expname
READOBJ-NEXT: Symbol: expname
READOBJ-NEXT: Symbol: __imp_aux_expname
READOBJ-NEXT: Symbol: #expname
READOBJ-EMPTY:
READOBJ-NEXT: File: test.dll
READOBJ-NEXT: Format: COFF-import-file-ARM64EC
Expand All @@ -51,8 +97,101 @@ Creating a new lib containing the existing lib:
RUN: llvm-lib -machine:arm64ec test.lib -out:test2.lib
RUN: llvm-nm --print-armap test2.lib | FileCheck -check-prefix=ARMAP %s


RUN: llvm-lib -machine:arm64ec -def:exportas.def -out:exportas.lib
RUN: llvm-nm --print-armap exportas.lib | FileCheck -check-prefix=EXPAS-ARMAP %s
RUN: llvm-readobj exportas.lib | FileCheck -check-prefix=EXPAS-READOBJ %s

EXPAS-ARMAP: Archive EC map
EXPAS-ARMAP-NEXT: #func1 in test.dll
EXPAS-ARMAP-NEXT: #func2 in test.dll
EXPAS-ARMAP-NEXT: #func3 in test.dll
EXPAS-ARMAP-NEXT: #func4 in test.dll
EXPAS-ARMAP-NEXT: __imp_aux_func1 in test.dll
EXPAS-ARMAP-NEXT: __imp_aux_func2 in test.dll
EXPAS-ARMAP-NEXT: __imp_aux_func3 in test.dll
EXPAS-ARMAP-NEXT: __imp_aux_func4 in test.dll
EXPAS-ARMAP-NEXT: __imp_data1 in test.dll
EXPAS-ARMAP-NEXT: __imp_data2 in test.dll
EXPAS-ARMAP-NEXT: __imp_func1 in test.dll
EXPAS-ARMAP-NEXT: __imp_func2 in test.dll
EXPAS-ARMAP-NEXT: __imp_func3 in test.dll
EXPAS-ARMAP-NEXT: __imp_func4 in test.dll
EXPAS-ARMAP-NEXT: func1 in test.dll
EXPAS-ARMAP-NEXT: func2 in test.dll
EXPAS-ARMAP-NEXT: func3 in test.dll
EXPAS-ARMAP-NEXT: func4 in test.dll

EXPAS-READOBJ: File: test.dll
EXPAS-READOBJ-NEXT: Format: COFF-import-file-ARM64EC
EXPAS-READOBJ-NEXT: Type: code
EXPAS-READOBJ-NEXT: Name type: export as
EXPAS-READOBJ-NEXT: Export name: func1
EXPAS-READOBJ-NEXT: Symbol: __imp_func1
EXPAS-READOBJ-NEXT: Symbol: func1
EXPAS-READOBJ-NEXT: Symbol: __imp_aux_func1
EXPAS-READOBJ-NEXT: Symbol: #func1
EXPAS-READOBJ-EMPTY:
EXPAS-READOBJ-NEXT: File: test.dll
EXPAS-READOBJ-NEXT: Format: COFF-import-file-ARM64EC
EXPAS-READOBJ-NEXT: Type: code
EXPAS-READOBJ-NEXT: Name type: export as
EXPAS-READOBJ-NEXT: Export name: func2
EXPAS-READOBJ-NEXT: Symbol: __imp_func2
EXPAS-READOBJ-NEXT: Symbol: func2
EXPAS-READOBJ-NEXT: Symbol: __imp_aux_func2
EXPAS-READOBJ-NEXT: Symbol: #func2
EXPAS-READOBJ-EMPTY:
EXPAS-READOBJ-NEXT: File: test.dll
EXPAS-READOBJ-NEXT: Format: COFF-import-file-ARM64EC
EXPAS-READOBJ-NEXT: Type: code
EXPAS-READOBJ-NEXT: Name type: export as
EXPAS-READOBJ-NEXT: Export name: #func3
EXPAS-READOBJ-NEXT: Symbol: __imp_func3
EXPAS-READOBJ-NEXT: Symbol: func3
EXPAS-READOBJ-NEXT: Symbol: __imp_aux_func3
EXPAS-READOBJ-NEXT: Symbol: #func3
EXPAS-READOBJ-EMPTY:
EXPAS-READOBJ-NEXT: File: test.dll
EXPAS-READOBJ-NEXT: Format: COFF-import-file-ARM64EC
EXPAS-READOBJ-NEXT: Type: code
EXPAS-READOBJ-NEXT: Name type: export as
EXPAS-READOBJ-NEXT: Export name: #func4
EXPAS-READOBJ-NEXT: Symbol: __imp_func4
EXPAS-READOBJ-NEXT: Symbol: func4
EXPAS-READOBJ-NEXT: Symbol: __imp_aux_func4
EXPAS-READOBJ-NEXT: Symbol: #func4
EXPAS-READOBJ-EMPTY:
EXPAS-READOBJ-NEXT: File: test.dll
EXPAS-READOBJ-NEXT: Format: COFF-import-file-ARM64EC
EXPAS-READOBJ-NEXT: Type: data
EXPAS-READOBJ-NEXT: Name type: export as
EXPAS-READOBJ-NEXT: Export name: #data1
EXPAS-READOBJ-NEXT: Symbol: __imp_data1
EXPAS-READOBJ-EMPTY:
EXPAS-READOBJ-NEXT: File: test.dll
EXPAS-READOBJ-NEXT: Format: COFF-import-file-ARM64EC
EXPAS-READOBJ-NEXT: Type: data
EXPAS-READOBJ-NEXT: Name type: export as
EXPAS-READOBJ-NEXT: Export name: data2
EXPAS-READOBJ-NEXT: Symbol: __imp_data2


#--- test.def
LIBRARY test.dll
EXPORTS
funcexp
#mangledfunc
?test_cpp_func@@YAHPEAX@Z
expname=impname
dataexp DATA

#--- exportas.def
LIBRARY test.dll
EXPORTS
#func1 EXPORTAS func1
func2 EXPORTAS func2
func3 EXPORTAS #func3
#func4 EXPORTAS #func4
data1 DATA EXPORTAS #data1
#data2 DATA EXPORTAS data2
Loading