Skip to content

Backport fixes for ARM64EC import libraries #84590

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

Merged
merged 5 commits into from
Mar 16, 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
1 change: 1 addition & 0 deletions lld/test/COFF/def-export-cpp.s
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

# IMPLIB: File: foo.dll
# IMPLIB: Name type: undecorate
# IMPLIB-NEXT: Export name: GetPathOnDisk
# IMPLIB-NEXT: Symbol: __imp_?GetPathOnDisk@@YA_NPEA_W@Z
# IMPLIB-NEXT: Symbol: ?GetPathOnDisk@@YA_NPEA_W@Z

Expand Down
13 changes: 13 additions & 0 deletions lld/test/COFF/def-export-stdcall.s
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,19 @@
# RUN: llvm-readobj --coff-exports %t.dll | FileCheck -check-prefix UNDECORATED-EXPORTS %s

# UNDECORATED-IMPLIB: Name type: noprefix
# UNDECORATED-IMPLIB-NEXT: Export name: _underscored
# UNDECORATED-IMPLIB-NEXT: __imp___underscored
# UNDECORATED-IMPLIB-NEXT: __underscored
# UNDECORATED-IMPLIB: Name type: undecorate
# UNDECORATED-IMPLIB-NEXT: Export name: fastcall
# UNDECORATED-IMPLIB-NEXT: __imp_@fastcall@8
# UNDECORATED-IMPLIB-NEXT: fastcall@8
# UNDECORATED-IMPLIB: Name type: undecorate
# UNDECORATED-IMPLIB-NEXT: Export name: stdcall
# UNDECORATED-IMPLIB-NEXT: __imp__stdcall@8
# UNDECORATED-IMPLIB-NEXT: _stdcall@8
# UNDECORATED-IMPLIB: Name type: undecorate
# UNDECORATED-IMPLIB-NEXT: Export name: vectorcall
# UNDECORATED-IMPLIB-NEXT: __imp_vectorcall@@8
# UNDECORATED-IMPLIB-NEXT: vectorcall@@8

Expand All @@ -30,12 +34,15 @@
# RUN: llvm-readobj --coff-exports %t.dll | FileCheck -check-prefix DECORATED-EXPORTS %s

# DECORATED-IMPLIB: Name type: name
# DECORATED-IMPLIB-NEXT: Export name: @fastcall@8
# DECORATED-IMPLIB-NEXT: __imp_@fastcall@8
# DECORATED-IMPLIB-NEXT: @fastcall@8
# DECORATED-IMPLIB: Name type: name
# DECORATED-IMPLIB-NEXT: Export name: _stdcall@8
# DECORATED-IMPLIB-NEXT: __imp__stdcall@8
# DECORATED-IMPLIB-NEXT: _stdcall@8
# DECORATED-IMPLIB: Name type: name
# DECORATED-IMPLIB-NEXT: Export name: vectorcall@@8
# DECORATED-IMPLIB-NEXT: __imp_vectorcall@@8
# DECORATED-IMPLIB-NEXT: vectorcall@@8

Expand All @@ -51,14 +58,17 @@
# RUN: llvm-readobj --coff-exports %t.dll | FileCheck -check-prefix DECORATED-MINGW-EXPORTS %s

# DECORATED-MINGW-IMPLIB: Name type: name
# DECORATED-MINGW-IMPLIB-NEXT: Export name: @fastcall@8
# DECORATED-MINGW-IMPLIB-NEXT: __imp_@fastcall@8
# DECORATED-MINGW-IMPLIB-NEXT: fastcall@8
# DECORATED-MINGW-IMPLIB: Name type: noprefix
# DECORATED-MINGW-IMPLIB-NEXT: Export name: stdcall@8
# DECORATED-MINGW-IMPLIB-NEXT: __imp__stdcall@8
# DECORATED-MINGW-IMPLIB-NEXT: _stdcall@8
# GNU tools don't support vectorcall, but this test is just to track that
# lld's behaviour remains consistent over time.
# DECORATED-MINGW-IMPLIB: Name type: name
# DECORATED-MINGW-IMPLIB-NEXT: Export name: vectorcall@@8
# DECORATED-MINGW-IMPLIB-NEXT: __imp_vectorcall@@8
# DECORATED-MINGW-IMPLIB-NEXT: vectorcall@@8

Expand All @@ -75,14 +85,17 @@
# RUN: llvm-readobj --coff-exports %t.dll | FileCheck -check-prefix MINGW-KILL-AT-EXPORTS %s

# MINGW-KILL-AT-IMPLIB: Name type: noprefix
# MINGW-KILL-AT-IMPLIB: Export name: fastcall
# MINGW-KILL-AT-IMPLIB: __imp__fastcall
# MINGW-KILL-AT-IMPLIB-NEXT: _fastcall
# MINGW-KILL-AT-IMPLIB: Name type: noprefix
# MINGW-KILL-AT-IMPLIB-NEXT: Export name: stdcall
# MINGW-KILL-AT-IMPLIB-NEXT: __imp__stdcall
# MINGW-KILL-AT-IMPLIB-NEXT: _stdcall
# GNU tools don't support vectorcall, but this test is just to track that
# lld's behaviour remains consistent over time.
# MINGW-KILL-AT-IMPLIB: Name type: noprefix
# MINGW-KILL-AT-IMPLIB-NEXT: Export name: vectorcall
# MINGW-KILL-AT-IMPLIB-NEXT: __imp__vectorcall
# MINGW-KILL-AT-IMPLIB-NEXT: _vectorcall

Expand Down
4 changes: 4 additions & 0 deletions lld/test/COFF/dllexport.s
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,19 @@
# RUN: llvm-readobj --coff-exports %t.dll | FileCheck -check-prefix DECORATED-EXPORTS %s

# DECORATED-IMPLIB: Name type: name
# DECORATED-IMPLIB-NEXT: Export name: @fastcall@8
# DECORATED-IMPLIB-NEXT: __imp_@fastcall@8
# DECORATED-IMPLIB-NEXT: @fastcall@8
# DECORATED-IMPLIB: Name type: name
# DECORATED-IMPLIB-NEXT: Export name: _stdcall@8
# DECORATED-IMPLIB-NEXT: __imp__stdcall@8
# DECORATED-IMPLIB-NEXT: _stdcall@8
# DECORATED-IMPLIB: Name type: noprefix
# DECORATED-IMPLIB-NEXT: Export name: _underscored
# DECORATED-IMPLIB-NEXT: __imp___underscored
# DECORATED-IMPLIB-NEXT: __underscored
# DECORATED-IMPLIB: Name type: name
# DECORATED-IMPLIB-NEXT: Export name: vectorcall@@8
# DECORATED-IMPLIB-NEXT: __imp_vectorcall@@8
# DECORATED-IMPLIB-NEXT: vectorcall@@8

Expand Down
5 changes: 4 additions & 1 deletion llvm/include/llvm/BinaryFormat/COFF.h
Original file line number Diff line number Diff line change
Expand Up @@ -716,7 +716,10 @@ enum ImportNameType : unsigned {
IMPORT_NAME_NOPREFIX = 2,
/// The import name is the public symbol name, but skipping the leading ?,
/// @, or optionally _, and truncating at the first @.
IMPORT_NAME_UNDECORATE = 3
IMPORT_NAME_UNDECORATE = 3,
/// The import name is specified as a separate string in the import library
/// object file.
IMPORT_NAME_EXPORTAS = 4
};

enum class GuardFlags : uint32_t {
Expand Down
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) {
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
35 changes: 32 additions & 3 deletions llvm/include/llvm/Object/COFFImportFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,16 @@
namespace llvm {
namespace object {

constexpr std::string_view ImportDescriptorPrefix = "__IMPORT_DESCRIPTOR_";
constexpr std::string_view NullImportDescriptorSymbolName =
"__NULL_IMPORT_DESCRIPTOR";
constexpr std::string_view NullThunkDataPrefix = "\x7f";
constexpr std::string_view NullThunkDataSuffix = "_NULL_THUNK_DATA";

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

public:
COFFImportFile(MemoryBufferRef Source)
: SymbolicFile(ID_COFFImportFile, Source) {}
Expand All @@ -36,9 +45,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 +75,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 All @@ -66,6 +94,7 @@ class COFFImportFile : public SymbolicFile {
uint16_t getMachine() const { return getCOFFImportHeader()->Machine; }

StringRef getFileFormatName() const;
StringRef getExportName() const;

private:
bool isData() const {
Expand Down
11 changes: 11 additions & 0 deletions llvm/lib/Object/ArchiveWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,13 @@ static bool isECObject(object::SymbolicFile &Obj) {
return false;
}

bool isImportDescriptor(StringRef Name) {
return Name.starts_with(ImportDescriptorPrefix) ||
Name == StringRef{NullImportDescriptorSymbolName} ||
(Name.starts_with(NullThunkDataPrefix) &&
Name.ends_with(NullThunkDataSuffix));
}

static Expected<std::vector<unsigned>> getSymbols(SymbolicFile *Obj,
uint16_t Index,
raw_ostream &SymNames,
Expand Down Expand Up @@ -704,6 +711,10 @@ static Expected<std::vector<unsigned>> getSymbols(SymbolicFile *Obj,
if (Map == &SymMap->Map) {
Ret.push_back(SymNames.tell());
SymNames << Name << '\0';
// If EC is enabled, then the import descriptors are NOT put into EC
// objects so we need to copy them to the EC map manually.
if (SymMap->UseECMap && isImportDescriptor(Name))
SymMap->ECMap[Name] = Index;
}
} else {
Ret.push_back(SymNames.tell());
Expand Down
Loading