Files
clang-p2996/lld/lib/Driver/WinLinkModuleDef.cpp
Rui Ueyama de18f9657b [PECOFF] Keep unmangled name in the export table descriptor
The export table descriptor is a data structure to keep information
about the export table. It contains a symbol name, and the name may
or may not be mangled.

We need unmangled names for the export table, so we demangle them
before writing them to the export table.

Obviously this is not a correct round-trip conversion. That could
drop a leading underscore from a symbol because that's
indistinguishable from a mangled name.

What we need to do is to keep unmangled names. This patch does that.

llvm-svn: 218345
2014-09-24 00:55:15 +00:00

296 lines
7.2 KiB
C++

//===- lib/Driver/WinLinkModuleDef.cpp ------------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief Windows module definition file parser.
///
//===----------------------------------------------------------------------===//
#include "lld/Driver/WinLinkModuleDef.h"
#include "llvm/ADT/StringSwitch.h"
namespace lld {
namespace moduledef {
Token Lexer::lex() {
for (;;) {
_buffer = _buffer.trim();
if (_buffer.empty() || _buffer[0] == '\0')
return Token(Kind::eof, _buffer);
switch (_buffer[0]) {
case ';': {
size_t end = _buffer.find('\n');
_buffer = (end == _buffer.npos) ? "" : _buffer.drop_front(end);
continue;
}
case '=':
_buffer = _buffer.drop_front();
return Token(Kind::equal, "=");
case ',':
_buffer = _buffer.drop_front();
return Token(Kind::comma, ",");
case '"': {
size_t end = _buffer.find('"', 1);
Token ret;
if (end == _buffer.npos) {
ret = Token(Kind::identifier, _buffer.substr(1, end));
_buffer = "";
} else {
ret = Token(Kind::identifier, _buffer.substr(1, end - 1));
_buffer = _buffer.drop_front(end + 1);
}
return ret;
}
default: {
size_t end = _buffer.find_first_not_of(
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789_.*~+!@#$%^&*()/");
StringRef word = _buffer.substr(0, end);
Kind kind = llvm::StringSwitch<Kind>(word)
.Case("BASE", Kind::kw_base)
.Case("DATA", Kind::kw_data)
.Case("EXPORTS", Kind::kw_exports)
.Case("HEAPSIZE", Kind::kw_heapsize)
.Case("LIBRARY", Kind::kw_library)
.Case("NAME", Kind::kw_name)
.Case("NONAME", Kind::kw_noname)
.Case("PRIVATE", Kind::kw_private)
.Case("STACKSIZE", Kind::kw_stacksize)
.Case("VERSION", Kind::kw_version)
.Default(Kind::identifier);
_buffer = (end == _buffer.npos) ? "" : _buffer.drop_front(end);
return Token(kind, word);
}
}
}
}
void Parser::consumeToken() {
if (_tokBuf.empty()) {
_tok = _lex.lex();
return;
}
_tok = _tokBuf.back();
_tokBuf.pop_back();
}
bool Parser::consumeTokenAsInt(uint64_t &result) {
consumeToken();
if (_tok._kind != Kind::identifier) {
ungetToken();
error(_tok, "Integer expected");
return false;
}
if (_tok._range.getAsInteger(10, result)) {
error(_tok, "Integer expected");
return false;
}
return true;
}
bool Parser::expectAndConsume(Kind kind, Twine msg) {
consumeToken();
if (_tok._kind != kind) {
error(_tok, msg);
return false;
}
return true;
}
void Parser::ungetToken() { _tokBuf.push_back(_tok); }
void Parser::error(const Token &tok, Twine msg) {
_lex.getSourceMgr().PrintMessage(
llvm::SMLoc::getFromPointer(tok._range.data()), llvm::SourceMgr::DK_Error,
msg);
}
bool Parser::parse(std::vector<Directive *> &ret) {
for (;;) {
Directive *dir = nullptr;
if (!parseOne(dir))
return false;
if (!dir)
return true;
ret.push_back(dir);
}
}
bool Parser::parseOne(Directive *&ret) {
consumeToken();
switch (_tok._kind) {
case Kind::eof:
return true;
case Kind::kw_exports: {
// EXPORTS
std::vector<PECOFFLinkingContext::ExportDesc> exports;
for (;;) {
PECOFFLinkingContext::ExportDesc desc;
if (!parseExport(desc))
break;
exports.push_back(desc);
}
ret = new (_alloc) Exports(exports);
return true;
}
case Kind::kw_heapsize: {
// HEAPSIZE
uint64_t reserve, commit;
if (!parseMemorySize(reserve, commit))
return false;
ret = new (_alloc) Heapsize(reserve, commit);
return true;
}
case Kind::kw_library: {
// LIBRARY
std::string name;
uint64_t baseaddr;
if (!parseName(name, baseaddr))
return false;
if (!StringRef(name).endswith_lower(".dll"))
name.append(".dll");
ret = new (_alloc) Library(name, baseaddr);
return true;
}
case Kind::kw_stacksize: {
// STACKSIZE
uint64_t reserve, commit;
if (!parseMemorySize(reserve, commit))
return false;
ret = new (_alloc) Stacksize(reserve, commit);
return true;
}
case Kind::kw_name: {
// NAME
std::string outputPath;
uint64_t baseaddr;
if (!parseName(outputPath, baseaddr))
return false;
ret = new (_alloc) Name(outputPath, baseaddr);
return true;
}
case Kind::kw_version: {
// VERSION
int major, minor;
if (!parseVersion(major, minor))
return false;
ret = new (_alloc) Version(major, minor);
return true;
}
default:
error(_tok, Twine("Unknown directive: ") + _tok._range);
return false;
}
}
bool Parser::parseExport(PECOFFLinkingContext::ExportDesc &result) {
consumeToken();
if (_tok._kind != Kind::identifier) {
ungetToken();
return false;
}
result.name = _tok._range;
result.externalName = result.name;
consumeToken();
if (_tok._kind == Kind::equal) {
consumeToken();
if (_tok._kind != Kind::identifier)
return false;
result.name = _tok._range;
} else {
ungetToken();
}
for (;;) {
consumeToken();
if (_tok._kind == Kind::identifier && _tok._range[0] == '@') {
_tok._range.drop_front().getAsInteger(10, result.ordinal);
consumeToken();
if (_tok._kind == Kind::kw_noname) {
result.noname = true;
} else {
ungetToken();
}
continue;
}
if (_tok._kind == Kind::kw_data) {
result.isData = true;
continue;
}
if (_tok._kind == Kind::kw_private) {
result.isPrivate = true;
continue;
}
ungetToken();
return true;
}
}
// HEAPSIZE/STACKSIZE reserve[,commit]
bool Parser::parseMemorySize(uint64_t &reserve, uint64_t &commit) {
if (!consumeTokenAsInt(reserve))
return false;
consumeToken();
if (_tok._kind != Kind::comma) {
ungetToken();
commit = 0;
return true;
}
if (!consumeTokenAsInt(commit))
return false;
return true;
}
// NAME [outputPath] [BASE=address]
bool Parser::parseName(std::string &outputPath, uint64_t &baseaddr) {
consumeToken();
if (_tok._kind == Kind::identifier) {
outputPath = _tok._range;
} else {
outputPath = "";
ungetToken();
return true;
}
consumeToken();
if (_tok._kind == Kind::kw_base) {
if (!expectAndConsume(Kind::equal, "'=' expected"))
return false;
if (!consumeTokenAsInt(baseaddr))
return false;
} else {
ungetToken();
baseaddr = 0;
}
return true;
}
// VERSION major[.minor]
bool Parser::parseVersion(int &major, int &minor) {
consumeToken();
if (_tok._kind != Kind::identifier)
return false;
StringRef v1, v2;
std::tie(v1, v2) = _tok._range.split('.');
if (v1.getAsInteger(10, major))
return false;
if (v2.empty()) {
minor = 0;
} else if (v2.getAsInteger(10, minor)) {
return false;
}
return true;
}
} // moddef
} // namespace lld