COFF: Don't assume !is64() means i386.

In many places we assumed that is64() means AMD64 and i386 otherwise.
This assumption is not sound because Windows also supports ARM.
The linker doesn't support ARM yet, but this is a first step.

llvm-svn: 243188
This commit is contained in:
Rui Ueyama 2015-07-25 00:20:06 +00:00
parent 15663c530e
commit 35ccb0f7d4
8 changed files with 51 additions and 24 deletions

View File

@ -252,17 +252,23 @@ ImportThunkChunk::ImportThunkChunk(Defined *S) : ImpSymbol(S) {
}
void ImportThunkChunk::getBaserels(std::vector<uint32_t> *Res) {
if (!Config->is64())
if (Config->MachineType == I386)
Res->push_back(getRVA() + 2);
}
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 = Config->is64()
? ImpSymbol->getRVA() - RVA - getSize()
: ImpSymbol->getRVA() + Config->ImageBase;
write32le(Buf + FileOff + 2, Operand);
switch (Config->MachineType) {
case AMD64:
write32le(Buf + FileOff + 2, ImpSymbol->getRVA() - RVA - getSize());
break;
case I386:
write32le(Buf + FileOff + 2, ImpSymbol->getRVA() + Config->ImageBase);
break;
default:
llvm_unreachable("unsupported machine type");
}
}
void LocalImportChunk::getBaserels(std::vector<uint32_t> *Res) {
@ -299,10 +305,17 @@ BaserelChunk::BaserelChunk(uint32_t Page, uint32_t *Begin, uint32_t *End) {
write32le(P, Page);
write32le(P + 4, Data.size());
P += 8;
uint16_t RelTy =
Config->is64() ? IMAGE_REL_BASED_DIR64 : IMAGE_REL_BASED_HIGHLOW;
for (uint32_t *I = Begin; I != End; ++I) {
write16le(P, (RelTy << 12) | (*I - Page));
switch (Config->MachineType) {
case AMD64:
write16le(P, (IMAGE_REL_BASED_DIR64 << 12) | (*I - Page));
break;
case I386:
write16le(P, (IMAGE_REL_BASED_HIGHLOW << 12) | (*I - Page));
break;
default:
llvm_unreachable("unsupported machine type");
}
P += 2;
}
}

View File

@ -21,6 +21,7 @@ namespace lld {
namespace coff {
using llvm::COFF::IMAGE_FILE_MACHINE_AMD64;
using llvm::COFF::IMAGE_FILE_MACHINE_I386;
using llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN;
using llvm::COFF::WindowsSubsystem;
using llvm::StringRef;
@ -28,6 +29,11 @@ class DefinedAbsolute;
class DefinedRelative;
class Undefined;
// Short aliases.
static const auto AMD64 = llvm::COFF::IMAGE_FILE_MACHINE_AMD64;
static const auto ARM = llvm::COFF::IMAGE_FILE_MACHINE_ARM;
static const auto I386 = llvm::COFF::IMAGE_FILE_MACHINE_I386;
// Represents an /export option.
struct Export {
StringRef Name;

View File

@ -391,12 +391,7 @@ void DelayLoadContents::create(Defined *H) {
size_t Base = Addresses.size();
for (DefinedImportData *S : Syms) {
Chunk *T;
if (Config->is64()) {
T = new ThunkChunkX64(S, Dir.get(), Helper);
} else {
T = new ThunkChunkX86(S, Dir.get(), Helper);
}
Chunk *T = newThunkChunk(S, Dir.get());
auto A = make_unique<DelayAddressChunk>(T);
Addresses.push_back(std::move(A));
Thunks.push_back(std::unique_ptr<Chunk>(T));
@ -430,6 +425,17 @@ void DelayLoadContents::create(Defined *H) {
make_unique<NullChunk>(sizeof(delay_import_directory_table_entry)));
}
Chunk *DelayLoadContents::newThunkChunk(DefinedImportData *S, Chunk *Dir) {
switch (Config->MachineType) {
case AMD64:
return new ThunkChunkX64(S, Dir, Helper);
case I386:
return new ThunkChunkX86(S, Dir, Helper);
default:
llvm_unreachable("unsupported machine type");
}
}
// Export table
// Read Microsoft PE/COFF spec 5.3 for details.

View File

@ -57,6 +57,8 @@ public:
uint64_t getDirSize();
private:
Chunk *newThunkChunk(DefinedImportData *S, Chunk *Dir);
Defined *Helper;
std::vector<DefinedImportData *> Imports;
std::vector<std::unique_ptr<Chunk>> Dirs;

View File

@ -108,7 +108,7 @@ LinkerDriver::parseDirectives(StringRef S) {
ErrorOr<Export> E = parseExport(Arg->getValue());
if (auto EC = E.getError())
return EC;
if (!Config->is64() && E->ExtName.startswith("_"))
if (Config->MachineType == I386 && E->ExtName.startswith("_"))
E->ExtName = E->ExtName.substr(1);
Config->Exports.push_back(E.get());
break;
@ -554,8 +554,8 @@ bool LinkerDriver::link(llvm::ArrayRef<const char *> ArgsArr) {
if (auto *Arg = Args.getLastArg(OPT_entry)) {
Config->Entry = addUndefined(mangle(Arg->getValue()));
} else if (Args.hasArg(OPT_dll) && !Config->NoEntry) {
StringRef S =
Config->is64() ? "_DllMainCRTStartup" : "__DllMainCRTStartup@12";
StringRef S = (Config->MachineType == I386) ? "__DllMainCRTStartup@12"
: "_DllMainCRTStartup";
Config->Entry = addUndefined(S);
} else if (!Config->NoEntry) {
// Windows specific -- If entry point name is not given, we need to
@ -575,7 +575,7 @@ bool LinkerDriver::link(llvm::ArrayRef<const char *> ArgsArr) {
ErrorOr<Export> E = parseExport(Arg->getValue());
if (E.getError())
return false;
if (!Config->is64() && !E->Name.startswith("_@?"))
if (Config->MachineType == I386 && !E->Name.startswith("_@?"))
E->Name = mangle(E->Name);
Config->Exports.push_back(E.get());
}
@ -595,10 +595,10 @@ bool LinkerDriver::link(llvm::ArrayRef<const char *> ArgsArr) {
// Handle /delayload
for (auto *Arg : Args.filtered(OPT_delayload)) {
Config->DelayLoads.insert(StringRef(Arg->getValue()).lower());
if (Config->is64()) {
Config->DelayLoadHelper = addUndefined("__delayLoadHelper2");
} else {
if (Config->MachineType == I386) {
Config->DelayLoadHelper = addUndefined("___delayLoadHelper2@8");
} else {
Config->DelayLoadHelper = addUndefined("__delayLoadHelper2");
}
}

View File

@ -428,7 +428,7 @@ std::error_code fixupExports() {
if (!E.ExtName.empty())
continue;
StringRef S = E.Sym->repl()->getName();
if (!Config->is64() && S.startswith("_"))
if (Config->MachineType == I386 && S.startswith("_"))
S = S.substr(1);
E.ExtName = S;
}

View File

@ -209,7 +209,7 @@ private:
unget();
}
if (!Config->is64() && !E.Name.startswith("_@?"))
if (Config->MachineType == I386 && !E.Name.startswith("_@?"))
E.Name = Alloc->save("_" + E.Name);
for (;;) {

View File

@ -287,7 +287,7 @@ StringRef SymbolTable::findMangle(StringRef Name) {
if (Symbol *Sym = find(Name))
if (!isa<Undefined>(Sym->Body))
return Name;
if (Config->is64())
if (Config->MachineType != I386)
return findByPrefix(("?" + Name + "@@Y").str());
if (!Name.startswith("_"))
return "";