[PECOFF] Parse /export optional arguments.

/EXPORT command line option can take an ordinal, NONAME flag, and DATA flag.
This patch is to parse these optional arguments.

llvm-svn: 197217
This commit is contained in:
Rui Ueyama 2013-12-13 08:42:52 +00:00
parent 37d25de459
commit fa561713f3
4 changed files with 81 additions and 12 deletions

View File

@ -57,6 +57,14 @@ public:
int minorVersion;
};
struct ExportDesc {
ExportDesc() : ordinal(-1), noname(false), isData(false) {}
std::string name;
int ordinal;
bool noname;
bool isData;
};
/// \brief Casting support
static inline bool classof(const LinkingContext *info) { return true; }
@ -219,8 +227,8 @@ public:
void setDosStub(ArrayRef<uint8_t> data) { _dosStub = data; }
ArrayRef<uint8_t> getDosStub() const { return _dosStub; }
void addDllExport(StringRef sym) { _dllExports.insert(sym); }
const std::set<std::string> &getDllExports() const { return _dllExports; }
void addDllExport(ExportDesc &desc) { _dllExports.push_back(desc); }
const std::vector<ExportDesc> &getDllExports() const { return _dllExports; }
StringRef allocate(StringRef ref) const {
char *x = _allocator.Allocate<char>(ref.size() + 1);
@ -301,7 +309,7 @@ private:
std::map<std::string, uint32_t> _sectionClearMask;
// DLLExport'ed symbols.
std::set<std::string> _dllExports;
std::vector<ExportDesc> _dllExports;
// List of files that will be removed on destruction.
std::vector<std::unique_ptr<llvm::FileRemover> > _tempFiles;

View File

@ -300,6 +300,41 @@ bool parseManifestUac(StringRef option, llvm::Optional<std::string> &level,
}
}
// Parse /export:name[,@ordinal[,NONAME]][,DATA].
bool parseExport(StringRef option, PECOFFLinkingContext::ExportDesc &ret) {
StringRef name;
StringRef rest;
llvm::tie(name, rest) = option.split(",");
if (name.empty())
return false;
ret.name = name;
for (;;) {
if (rest.empty())
return true;
StringRef arg;
llvm::tie(arg, rest) = rest.split(",");
if (arg.equals_lower("noname")) {
if (ret.ordinal < 0)
return false;
ret.noname = true;
continue;
}
if (arg.equals_lower("data")) {
ret.isData = true;
continue;
}
if (arg.startswith("@")) {
int ordinal;
if (arg.substr(1).getAsInteger(0, ordinal))
return false;
ret.ordinal = ordinal;
continue;
}
return false;
}
}
StringRef replaceExtension(PECOFFLinkingContext &ctx,
StringRef path, StringRef extension) {
SmallString<128> val = path;
@ -840,9 +875,15 @@ WinLinkDriver::parse(int argc, const char *argv[], PECOFFLinkingContext &ctx,
ctx.setEntrySymbolName(ctx.allocate(inputArg->getValue()));
break;
case OPT_export:
ctx.addDllExport(inputArg->getValue());
case OPT_export: {
PECOFFLinkingContext::ExportDesc desc;
if (!parseExport(inputArg->getValue(), desc)) {
diagnostics << "Error: malformed /export option\n";
return false;
}
ctx.addDllExport(desc);
break;
}
case OPT_libpath:
ctx.appendInputSearchPath(ctx.allocate(inputArg->getValue()));

View File

@ -30,10 +30,10 @@ static bool getExportedAtoms(const PECOFFLinkingContext &ctx, MutableFile *file,
for (const DefinedAtom *atom : file->defined())
definedAtoms[atom->name()] = atom;
for (StringRef dllExport : ctx.getDllExports()) {
auto it = definedAtoms.find(ctx.decorateSymbol(dllExport));
for (const PECOFFLinkingContext::ExportDesc &desc : ctx.getDllExports()) {
auto it = definedAtoms.find(ctx.decorateSymbol(desc.name));
if (it == definedAtoms.end()) {
llvm::errs() << "Symbol <" << dllExport
llvm::errs() << "Symbol <" << desc.name
<< "> is exported but not defined.\n";
return false;
}

View File

@ -157,10 +157,30 @@ TEST_F(WinLinkParserTest, AlternateName) {
}
TEST_F(WinLinkParserTest, Export) {
EXPECT_TRUE(parse("link.exe", "/export:_foo", "a.out", nullptr));
const std::set<std::string> &exports = _context.getDllExports();
EXPECT_TRUE(exports.count("_foo") == 1);
EXPECT_TRUE(exports.count("nosuchsym") == 0);
EXPECT_TRUE(parse("link.exe", "/export:foo", "a.out", nullptr));
const std::vector<PECOFFLinkingContext::ExportDesc> &exports =
_context.getDllExports();
EXPECT_TRUE(exports.size() == 1);
EXPECT_EQ("foo", exports[0].name);
EXPECT_EQ(-1, exports[0].ordinal);
EXPECT_FALSE(exports[0].noname);
EXPECT_FALSE(exports[0].isData);
}
TEST_F(WinLinkParserTest, ExportWithOptions) {
EXPECT_TRUE(parse("link.exe", "/export:foo,@8,noname,data",
"/export:bar,@10,data", "a.out", nullptr));
const std::vector<PECOFFLinkingContext::ExportDesc> &exports =
_context.getDllExports();
EXPECT_TRUE(exports.size() == 2);
EXPECT_EQ("foo", exports[0].name);
EXPECT_EQ(8, exports[0].ordinal);
EXPECT_TRUE(exports[0].noname);
EXPECT_TRUE(exports[0].isData);
EXPECT_EQ("bar", exports[1].name);
EXPECT_EQ(10, exports[1].ordinal);
EXPECT_FALSE(exports[1].noname);
EXPECT_TRUE(exports[1].isData);
}
TEST_F(WinLinkParserTest, MachineX86) {