#include "llvm-c/lto.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/System/Errno.h"
#include "llvm/System/Path.h"
+#include "llvm/System/Program.h"
+#include <cerrno>
#include <cstdlib>
#include <cstring>
+#include <fstream>
#include <list>
#include <vector>
-#include <cerrno>
using namespace llvm;
int api_version = 0;
int gold_version = 0;
+ bool generate_api_file = false;
+ const char *as_path = NULL;
+
struct claimed_file {
lto_module_t M;
void *handle;
- void *buf;
std::vector<ld_plugin_symbol> syms;
};
//output_type = LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC;
break;
case LDPT_OPTION:
- (*message)(LDPL_WARNING, "Ignoring flag %s", tv->tv_u.tv_string);
+ if (strcmp("generate-api-file", tv->tv_u.tv_string) == 0) {
+ generate_api_file = true;
+ } else if (strncmp("as=", tv->tv_u.tv_string, 3) == 0) {
+ if (as_path) {
+ (*message)(LDPL_WARNING, "Path to as specified twice. "
+ "Discarding %s", tv->tv_u.tv_string);
+ } else {
+ as_path = strdup(tv->tv_u.tv_string + 3);
+ }
+ } else {
+ (*message)(LDPL_WARNING, "Ignoring flag %s", tv->tv_u.tv_string);
+ }
break;
case LDPT_REGISTER_CLAIM_FILE_HOOK: {
ld_plugin_register_claim_file callback;
}
}
- if (!registeredClaimFile || !registeredAllSymbolsRead || !registeredCleanup ||
- !add_symbols || !get_symbols || !add_input_file) {
- (*message)(LDPL_ERROR, "Not all hooks registered for LLVMgold.");
+ if (!registeredClaimFile) {
+ (*message)(LDPL_ERROR, "register_claim_file not passed to LLVMgold.");
+ return LDPS_ERR;
+ }
+ if (!add_symbols) {
+ (*message)(LDPL_ERROR, "add_symbols not passed to LLVMgold.");
return LDPS_ERR;
}
ld_plugin_status claim_file_hook(const ld_plugin_input_file *file,
int *claimed) {
void *buf = NULL;
- printf("%s,%d,%d\n",file->name, file->offset, file->filesize);
- // If set, this means gold found IR in an ELF section. LLVM doesn't wrap its
- // IR in ELF, so we know it's not us. But it can also be an .a file containing
- // LLVM IR.
if (file->offset) {
+ // Gold has found what might be IR part-way inside of a file, such as
+ // an .a archive.
if (lseek(file->fd, file->offset, SEEK_SET) == -1) {
- (*message)(LDPL_ERROR,
+ (*message)(LDPL_ERROR,
"Failed to seek to archive member of %s at offset %d: %s\n",
file->name,
- file->offset, strerror(errno));
+ file->offset, sys::StrError(errno).c_str());
return LDPS_ERR;
}
buf = malloc(file->filesize);
if (!buf) {
- (*message)(LDPL_ERROR,
+ (*message)(LDPL_ERROR,
"Failed to allocate buffer for archive member of size: %d\n",
file->filesize);
return LDPS_ERR;
}
if (read(file->fd, buf, file->filesize) != file->filesize) {
- (*message)(LDPL_ERROR,
- "Failed to read archive member of %s at offset %d: %s\n",
+ (*message)(LDPL_ERROR,
+ "Failed to read archive member of %s at offset %d: %s\n",
file->name,
- file->offset,
- strerror(errno));
+ file->offset,
+ sys::StrError(errno).c_str());
free(buf);
return LDPS_ERR;
}
Modules.resize(Modules.size() + 1);
claimed_file &cf = Modules.back();
- cf.M = buf ? lto_module_create_from_memory(buf, file->filesize) :
- lto_module_create(file->name);
- cf.buf = buf;
+ cf.M = buf ? lto_module_create_from_memory(buf, file->filesize) :
+ lto_module_create(file->name);
+ free(buf);
if (!cf.M) {
(*message)(LDPL_ERROR, "Failed to create LLVM module: %s",
lto_get_error_message());
break;
default:
(*message)(LDPL_ERROR, "Unknown scope attribute: %d", scope);
- free(buf);
return LDPS_ERR;
}
case LTO_SYMBOL_DEFINITION_WEAK:
sym.def = LDPK_WEAKDEF;
break;
+ case LTO_SYMBOL_DEFINITION_WEAKUNDEF:
+ sym.def = LDPK_WEAKUNDEF;
+ break;
default:
(*message)(LDPL_ERROR, "Unknown definition attribute: %d", definition);
- free(buf);
return LDPS_ERR;
}
if (!cf.syms.empty()) {
if ((*add_symbols)(cf.handle, cf.syms.size(), &cf.syms[0]) != LDPS_OK) {
(*message)(LDPL_ERROR, "Unable to add symbols!");
- free(buf);
return LDPS_ERR;
}
}
E = Modules.end(); I != E; ++I)
lto_codegen_add_module(cg, I->M);
+ std::ofstream api_file;
+ if (generate_api_file) {
+ api_file.open("apifile.txt", std::ofstream::out | std::ofstream::trunc);
+ if (!api_file.is_open()) {
+ (*message)(LDPL_FATAL, "Unable to open apifile.txt for writing.");
+ abort();
+ }
+ }
+
// If we don't preserve any symbols, libLTO will assume that all symbols are
// needed. Keep all symbols unless we're producing a final executable.
if (output_type == LTO_CODEGEN_PIC_MODEL_STATIC) {
E = Modules.end(); I != E; ++I) {
(*get_symbols)(I->handle, I->syms.size(), &I->syms[0]);
for (unsigned i = 0, e = I->syms.size(); i != e; i++) {
- (*message)(LDPL_WARNING, "def: %d visibility: %d resolution %d",
- I->syms[i].def, I->syms[i].visibility, I->syms[i].resolution);
- if (I->syms[i].resolution == LDPR_PREVAILING_DEF) {
+ if (I->syms[i].resolution == LDPR_PREVAILING_DEF ||
+ (I->syms[i].def == LDPK_COMMON &&
+ I->syms[i].resolution == LDPR_RESOLVED_IR)) {
lto_codegen_add_must_preserve_symbol(cg, I->syms[i].name);
anySymbolsPreserved = true;
+
+ if (generate_api_file)
+ api_file << I->syms[i].name << "\n";
}
}
}
+ if (generate_api_file)
+ api_file.close();
+
if (!anySymbolsPreserved) {
// This entire file is unnecessary!
lto_codegen_dispose(cg);
lto_codegen_set_pic_model(cg, output_type);
lto_codegen_set_debug_model(cg, LTO_DEBUG_MODEL_DWARF);
+ if (as_path) {
+ sys::Path p = sys::Program::FindProgramByName(as_path);
+ lto_codegen_set_assembler_path(cg, p.c_str());
+ }
size_t bufsize = 0;
const char *buffer = static_cast<const char *>(lto_codegen_compile(cg,
objFile->close();
lto_codegen_dispose(cg);
- for (std::list<claimed_file>::iterator I = Modules.begin(),
- E = Modules.end(); I != E; ++I) {
- free(I->buf);
- }
if ((*add_input_file)(const_cast<char*>(uniqueObjPath.c_str())) != LDPS_OK) {
(*message)(LDPL_ERROR, "Unable to add .o file to the link.");