[lld][WebAssembly] Replace config-> with ctx.arg.
Change the global variable reference to a member access of another variable `ctx`. In the future, we may pass through `ctx` to functions to eliminate global variables. Pull Request: https://github.com/llvm/llvm-project/pull/119835
This commit is contained in:
@@ -126,17 +126,9 @@ struct Config {
|
||||
llvm::SmallVector<uint8_t, 0> buildIdVector;
|
||||
};
|
||||
|
||||
struct ConfigWrapper {
|
||||
Config c;
|
||||
Config *operator->() { return &c; }
|
||||
};
|
||||
|
||||
// The only instance of Configuration struct.
|
||||
extern ConfigWrapper config;
|
||||
|
||||
// The Ctx object hold all other (non-configuration) global state.
|
||||
struct Ctx {
|
||||
Config &arg;
|
||||
Config arg;
|
||||
|
||||
llvm::SmallVector<ObjFile *, 0> objectFiles;
|
||||
llvm::SmallVector<StubFile *, 0> stubFiles;
|
||||
|
||||
@@ -44,17 +44,16 @@ using namespace llvm::sys;
|
||||
using namespace llvm::wasm;
|
||||
|
||||
namespace lld::wasm {
|
||||
ConfigWrapper config;
|
||||
Ctx ctx;
|
||||
|
||||
void errorOrWarn(const llvm::Twine &msg) {
|
||||
if (config->noinhibitExec)
|
||||
if (ctx.arg.noinhibitExec)
|
||||
warn(msg);
|
||||
else
|
||||
error(msg);
|
||||
}
|
||||
|
||||
Ctx::Ctx() : arg(config.c) {}
|
||||
Ctx::Ctx() {}
|
||||
|
||||
void Ctx::reset() {
|
||||
arg.~Config();
|
||||
@@ -268,7 +267,7 @@ opt::InputArgList WasmOptTable::parse(ArrayRef<const char *> argv) {
|
||||
static void readImportFile(StringRef filename) {
|
||||
if (std::optional<MemoryBufferRef> buf = readFile(filename))
|
||||
for (StringRef sym : args::getLines(*buf))
|
||||
config->allowUndefinedSymbols.insert(sym);
|
||||
ctx.arg.allowUndefinedSymbols.insert(sym);
|
||||
}
|
||||
|
||||
// Returns slices of MB by parsing MB as an archive file.
|
||||
@@ -345,7 +344,7 @@ void LinkerDriver::addFile(StringRef path) {
|
||||
case file_magic::bitcode:
|
||||
case file_magic::wasm_object: {
|
||||
auto obj = createObjectFile(mbref, "", 0, inLib);
|
||||
if (config->isStatic && isa<SharedFile>(obj)) {
|
||||
if (ctx.arg.isStatic && isa<SharedFile>(obj)) {
|
||||
error("attempted static link of dynamic object " + path);
|
||||
break;
|
||||
}
|
||||
@@ -364,7 +363,7 @@ void LinkerDriver::addFile(StringRef path) {
|
||||
}
|
||||
|
||||
static std::optional<std::string> findFromSearchPaths(StringRef path) {
|
||||
for (StringRef dir : config->searchPaths)
|
||||
for (StringRef dir : ctx.arg.searchPaths)
|
||||
if (std::optional<std::string> s = findFile(dir, path))
|
||||
return s;
|
||||
return std::nullopt;
|
||||
@@ -373,8 +372,8 @@ static std::optional<std::string> findFromSearchPaths(StringRef path) {
|
||||
// This is for -l<basename>. We'll look for lib<basename>.a from
|
||||
// search paths.
|
||||
static std::optional<std::string> searchLibraryBaseName(StringRef name) {
|
||||
for (StringRef dir : config->searchPaths) {
|
||||
if (!config->isStatic)
|
||||
for (StringRef dir : ctx.arg.searchPaths) {
|
||||
if (!ctx.arg.isStatic)
|
||||
if (std::optional<std::string> s = findFile(dir, "lib" + name + ".so"))
|
||||
return s;
|
||||
if (std::optional<std::string> s = findFile(dir, "lib" + name + ".a"))
|
||||
@@ -408,10 +407,10 @@ void LinkerDriver::createFiles(opt::InputArgList &args) {
|
||||
addFile(arg->getValue());
|
||||
break;
|
||||
case OPT_Bstatic:
|
||||
config->isStatic = true;
|
||||
ctx.arg.isStatic = true;
|
||||
break;
|
||||
case OPT_Bdynamic:
|
||||
config->isStatic = false;
|
||||
ctx.arg.isStatic = false;
|
||||
break;
|
||||
case OPT_whole_archive:
|
||||
inWholeArchive = true;
|
||||
@@ -527,99 +526,98 @@ getBuildId(opt::InputArgList &args) {
|
||||
|
||||
// Initializes Config members by the command line options.
|
||||
static void readConfigs(opt::InputArgList &args) {
|
||||
config->allowMultipleDefinition =
|
||||
ctx.arg.allowMultipleDefinition =
|
||||
hasZOption(args, "muldefs") ||
|
||||
args.hasFlag(OPT_allow_multiple_definition,
|
||||
OPT_no_allow_multiple_definition, false);
|
||||
config->bsymbolic = args.hasArg(OPT_Bsymbolic);
|
||||
config->checkFeatures =
|
||||
ctx.arg.bsymbolic = args.hasArg(OPT_Bsymbolic);
|
||||
ctx.arg.checkFeatures =
|
||||
args.hasFlag(OPT_check_features, OPT_no_check_features, true);
|
||||
config->compressRelocations = args.hasArg(OPT_compress_relocations);
|
||||
config->demangle = args.hasFlag(OPT_demangle, OPT_no_demangle, true);
|
||||
config->disableVerify = args.hasArg(OPT_disable_verify);
|
||||
config->emitRelocs = args.hasArg(OPT_emit_relocs);
|
||||
config->experimentalPic = args.hasArg(OPT_experimental_pic);
|
||||
config->entry = getEntry(args);
|
||||
config->exportAll = args.hasArg(OPT_export_all);
|
||||
config->exportTable = args.hasArg(OPT_export_table);
|
||||
config->growableTable = args.hasArg(OPT_growable_table);
|
||||
config->noinhibitExec = args.hasArg(OPT_noinhibit_exec);
|
||||
ctx.arg.compressRelocations = args.hasArg(OPT_compress_relocations);
|
||||
ctx.arg.demangle = args.hasFlag(OPT_demangle, OPT_no_demangle, true);
|
||||
ctx.arg.disableVerify = args.hasArg(OPT_disable_verify);
|
||||
ctx.arg.emitRelocs = args.hasArg(OPT_emit_relocs);
|
||||
ctx.arg.experimentalPic = args.hasArg(OPT_experimental_pic);
|
||||
ctx.arg.entry = getEntry(args);
|
||||
ctx.arg.exportAll = args.hasArg(OPT_export_all);
|
||||
ctx.arg.exportTable = args.hasArg(OPT_export_table);
|
||||
ctx.arg.growableTable = args.hasArg(OPT_growable_table);
|
||||
ctx.arg.noinhibitExec = args.hasArg(OPT_noinhibit_exec);
|
||||
|
||||
if (args.hasArg(OPT_import_memory_with_name)) {
|
||||
config->memoryImport =
|
||||
ctx.arg.memoryImport =
|
||||
args.getLastArgValue(OPT_import_memory_with_name).split(",");
|
||||
} else if (args.hasArg(OPT_import_memory)) {
|
||||
config->memoryImport =
|
||||
ctx.arg.memoryImport =
|
||||
std::pair<llvm::StringRef, llvm::StringRef>(defaultModule, memoryName);
|
||||
} else {
|
||||
config->memoryImport =
|
||||
ctx.arg.memoryImport =
|
||||
std::optional<std::pair<llvm::StringRef, llvm::StringRef>>();
|
||||
}
|
||||
|
||||
if (args.hasArg(OPT_export_memory_with_name)) {
|
||||
config->memoryExport =
|
||||
args.getLastArgValue(OPT_export_memory_with_name);
|
||||
ctx.arg.memoryExport = args.getLastArgValue(OPT_export_memory_with_name);
|
||||
} else if (args.hasArg(OPT_export_memory)) {
|
||||
config->memoryExport = memoryName;
|
||||
ctx.arg.memoryExport = memoryName;
|
||||
} else {
|
||||
config->memoryExport = std::optional<llvm::StringRef>();
|
||||
ctx.arg.memoryExport = std::optional<llvm::StringRef>();
|
||||
}
|
||||
|
||||
config->sharedMemory = args.hasArg(OPT_shared_memory);
|
||||
config->soName = args.getLastArgValue(OPT_soname);
|
||||
config->importTable = args.hasArg(OPT_import_table);
|
||||
config->importUndefined = args.hasArg(OPT_import_undefined);
|
||||
config->ltoo = args::getInteger(args, OPT_lto_O, 2);
|
||||
if (config->ltoo > 3)
|
||||
error("invalid optimization level for LTO: " + Twine(config->ltoo));
|
||||
ctx.arg.sharedMemory = args.hasArg(OPT_shared_memory);
|
||||
ctx.arg.soName = args.getLastArgValue(OPT_soname);
|
||||
ctx.arg.importTable = args.hasArg(OPT_import_table);
|
||||
ctx.arg.importUndefined = args.hasArg(OPT_import_undefined);
|
||||
ctx.arg.ltoo = args::getInteger(args, OPT_lto_O, 2);
|
||||
if (ctx.arg.ltoo > 3)
|
||||
error("invalid optimization level for LTO: " + Twine(ctx.arg.ltoo));
|
||||
unsigned ltoCgo =
|
||||
args::getInteger(args, OPT_lto_CGO, args::getCGOptLevel(config->ltoo));
|
||||
args::getInteger(args, OPT_lto_CGO, args::getCGOptLevel(ctx.arg.ltoo));
|
||||
if (auto level = CodeGenOpt::getLevel(ltoCgo))
|
||||
config->ltoCgo = *level;
|
||||
ctx.arg.ltoCgo = *level;
|
||||
else
|
||||
error("invalid codegen optimization level for LTO: " + Twine(ltoCgo));
|
||||
config->ltoPartitions = args::getInteger(args, OPT_lto_partitions, 1);
|
||||
config->ltoObjPath = args.getLastArgValue(OPT_lto_obj_path_eq);
|
||||
config->ltoDebugPassManager = args.hasArg(OPT_lto_debug_pass_manager);
|
||||
config->mapFile = args.getLastArgValue(OPT_Map);
|
||||
config->optimize = args::getInteger(args, OPT_O, 1);
|
||||
config->outputFile = args.getLastArgValue(OPT_o);
|
||||
config->relocatable = args.hasArg(OPT_relocatable);
|
||||
config->gcSections =
|
||||
args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, !config->relocatable);
|
||||
ctx.arg.ltoPartitions = args::getInteger(args, OPT_lto_partitions, 1);
|
||||
ctx.arg.ltoObjPath = args.getLastArgValue(OPT_lto_obj_path_eq);
|
||||
ctx.arg.ltoDebugPassManager = args.hasArg(OPT_lto_debug_pass_manager);
|
||||
ctx.arg.mapFile = args.getLastArgValue(OPT_Map);
|
||||
ctx.arg.optimize = args::getInteger(args, OPT_O, 1);
|
||||
ctx.arg.outputFile = args.getLastArgValue(OPT_o);
|
||||
ctx.arg.relocatable = args.hasArg(OPT_relocatable);
|
||||
ctx.arg.gcSections =
|
||||
args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, !ctx.arg.relocatable);
|
||||
for (auto *arg : args.filtered(OPT_keep_section))
|
||||
config->keepSections.insert(arg->getValue());
|
||||
config->mergeDataSegments =
|
||||
ctx.arg.keepSections.insert(arg->getValue());
|
||||
ctx.arg.mergeDataSegments =
|
||||
args.hasFlag(OPT_merge_data_segments, OPT_no_merge_data_segments,
|
||||
!config->relocatable);
|
||||
config->pie = args.hasFlag(OPT_pie, OPT_no_pie, false);
|
||||
config->printGcSections =
|
||||
!ctx.arg.relocatable);
|
||||
ctx.arg.pie = args.hasFlag(OPT_pie, OPT_no_pie, false);
|
||||
ctx.arg.printGcSections =
|
||||
args.hasFlag(OPT_print_gc_sections, OPT_no_print_gc_sections, false);
|
||||
config->saveTemps = args.hasArg(OPT_save_temps);
|
||||
config->searchPaths = args::getStrings(args, OPT_library_path);
|
||||
config->shared = args.hasArg(OPT_shared);
|
||||
config->shlibSigCheck = !args.hasArg(OPT_no_shlib_sigcheck);
|
||||
config->stripAll = args.hasArg(OPT_strip_all);
|
||||
config->stripDebug = args.hasArg(OPT_strip_debug);
|
||||
config->stackFirst = args.hasArg(OPT_stack_first);
|
||||
config->trace = args.hasArg(OPT_trace);
|
||||
config->thinLTOCacheDir = args.getLastArgValue(OPT_thinlto_cache_dir);
|
||||
config->thinLTOCachePolicy = CHECK(
|
||||
ctx.arg.saveTemps = args.hasArg(OPT_save_temps);
|
||||
ctx.arg.searchPaths = args::getStrings(args, OPT_library_path);
|
||||
ctx.arg.shared = args.hasArg(OPT_shared);
|
||||
ctx.arg.shlibSigCheck = !args.hasArg(OPT_no_shlib_sigcheck);
|
||||
ctx.arg.stripAll = args.hasArg(OPT_strip_all);
|
||||
ctx.arg.stripDebug = args.hasArg(OPT_strip_debug);
|
||||
ctx.arg.stackFirst = args.hasArg(OPT_stack_first);
|
||||
ctx.arg.trace = args.hasArg(OPT_trace);
|
||||
ctx.arg.thinLTOCacheDir = args.getLastArgValue(OPT_thinlto_cache_dir);
|
||||
ctx.arg.thinLTOCachePolicy = CHECK(
|
||||
parseCachePruningPolicy(args.getLastArgValue(OPT_thinlto_cache_policy)),
|
||||
"--thinlto-cache-policy: invalid cache policy");
|
||||
config->thinLTOEmitImportsFiles = args.hasArg(OPT_thinlto_emit_imports_files);
|
||||
config->thinLTOEmitIndexFiles = args.hasArg(OPT_thinlto_emit_index_files) ||
|
||||
ctx.arg.thinLTOEmitImportsFiles = args.hasArg(OPT_thinlto_emit_imports_files);
|
||||
ctx.arg.thinLTOEmitIndexFiles = args.hasArg(OPT_thinlto_emit_index_files) ||
|
||||
args.hasArg(OPT_thinlto_index_only) ||
|
||||
args.hasArg(OPT_thinlto_index_only_eq);
|
||||
config->thinLTOIndexOnly = args.hasArg(OPT_thinlto_index_only) ||
|
||||
ctx.arg.thinLTOIndexOnly = args.hasArg(OPT_thinlto_index_only) ||
|
||||
args.hasArg(OPT_thinlto_index_only_eq);
|
||||
config->thinLTOIndexOnlyArg = args.getLastArgValue(OPT_thinlto_index_only_eq);
|
||||
config->thinLTOObjectSuffixReplace =
|
||||
ctx.arg.thinLTOIndexOnlyArg = args.getLastArgValue(OPT_thinlto_index_only_eq);
|
||||
ctx.arg.thinLTOObjectSuffixReplace =
|
||||
getOldNewOptions(args, OPT_thinlto_object_suffix_replace_eq);
|
||||
std::tie(config->thinLTOPrefixReplaceOld, config->thinLTOPrefixReplaceNew,
|
||||
config->thinLTOPrefixReplaceNativeObject) =
|
||||
std::tie(ctx.arg.thinLTOPrefixReplaceOld, ctx.arg.thinLTOPrefixReplaceNew,
|
||||
ctx.arg.thinLTOPrefixReplaceNativeObject) =
|
||||
getOldNewOptionsExtra(args, OPT_thinlto_prefix_replace_eq);
|
||||
if (config->thinLTOEmitIndexFiles && !config->thinLTOIndexOnly) {
|
||||
if (ctx.arg.thinLTOEmitIndexFiles && !ctx.arg.thinLTOIndexOnly) {
|
||||
if (args.hasArg(OPT_thinlto_object_suffix_replace_eq))
|
||||
error("--thinlto-object-suffix-replace is not supported with "
|
||||
"--thinlto-emit-index-files");
|
||||
@@ -627,45 +625,45 @@ static void readConfigs(opt::InputArgList &args) {
|
||||
error("--thinlto-prefix-replace is not supported with "
|
||||
"--thinlto-emit-index-files");
|
||||
}
|
||||
if (!config->thinLTOPrefixReplaceNativeObject.empty() &&
|
||||
config->thinLTOIndexOnlyArg.empty()) {
|
||||
if (!ctx.arg.thinLTOPrefixReplaceNativeObject.empty() &&
|
||||
ctx.arg.thinLTOIndexOnlyArg.empty()) {
|
||||
error("--thinlto-prefix-replace=old_dir;new_dir;obj_dir must be used with "
|
||||
"--thinlto-index-only=");
|
||||
}
|
||||
config->unresolvedSymbols = getUnresolvedSymbolPolicy(args);
|
||||
config->whyExtract = args.getLastArgValue(OPT_why_extract);
|
||||
ctx.arg.unresolvedSymbols = getUnresolvedSymbolPolicy(args);
|
||||
ctx.arg.whyExtract = args.getLastArgValue(OPT_why_extract);
|
||||
errorHandler().verbose = args.hasArg(OPT_verbose);
|
||||
LLVM_DEBUG(errorHandler().verbose = true);
|
||||
|
||||
config->tableBase = args::getInteger(args, OPT_table_base, 0);
|
||||
config->globalBase = args::getInteger(args, OPT_global_base, 0);
|
||||
config->initialHeap = args::getInteger(args, OPT_initial_heap, 0);
|
||||
config->initialMemory = args::getInteger(args, OPT_initial_memory, 0);
|
||||
config->maxMemory = args::getInteger(args, OPT_max_memory, 0);
|
||||
config->noGrowableMemory = args.hasArg(OPT_no_growable_memory);
|
||||
config->zStackSize =
|
||||
ctx.arg.tableBase = args::getInteger(args, OPT_table_base, 0);
|
||||
ctx.arg.globalBase = args::getInteger(args, OPT_global_base, 0);
|
||||
ctx.arg.initialHeap = args::getInteger(args, OPT_initial_heap, 0);
|
||||
ctx.arg.initialMemory = args::getInteger(args, OPT_initial_memory, 0);
|
||||
ctx.arg.maxMemory = args::getInteger(args, OPT_max_memory, 0);
|
||||
ctx.arg.noGrowableMemory = args.hasArg(OPT_no_growable_memory);
|
||||
ctx.arg.zStackSize =
|
||||
args::getZOptionValue(args, OPT_z, "stack-size", WasmPageSize);
|
||||
|
||||
// -Bdynamic by default if -pie or -shared is specified.
|
||||
if (config->pie || config->shared)
|
||||
config->isStatic = false;
|
||||
if (ctx.arg.pie || ctx.arg.shared)
|
||||
ctx.arg.isStatic = false;
|
||||
|
||||
if (config->maxMemory != 0 && config->noGrowableMemory) {
|
||||
if (ctx.arg.maxMemory != 0 && ctx.arg.noGrowableMemory) {
|
||||
// Erroring out here is simpler than defining precedence rules.
|
||||
error("--max-memory is incompatible with --no-growable-memory");
|
||||
}
|
||||
|
||||
// Default value of exportDynamic depends on `-shared`
|
||||
config->exportDynamic =
|
||||
args.hasFlag(OPT_export_dynamic, OPT_no_export_dynamic, config->shared);
|
||||
ctx.arg.exportDynamic =
|
||||
args.hasFlag(OPT_export_dynamic, OPT_no_export_dynamic, ctx.arg.shared);
|
||||
|
||||
// Parse wasm32/64.
|
||||
if (auto *arg = args.getLastArg(OPT_m)) {
|
||||
StringRef s = arg->getValue();
|
||||
if (s == "wasm32")
|
||||
config->is64 = false;
|
||||
ctx.arg.is64 = false;
|
||||
else if (s == "wasm64")
|
||||
config->is64 = true;
|
||||
ctx.arg.is64 = true;
|
||||
else
|
||||
error("invalid target architecture: " + s);
|
||||
}
|
||||
@@ -679,36 +677,36 @@ static void readConfigs(opt::InputArgList &args) {
|
||||
error(arg->getSpelling() + ": expected a positive integer, but got '" +
|
||||
arg->getValue() + "'");
|
||||
parallel::strategy = hardware_concurrency(threads);
|
||||
config->thinLTOJobs = v;
|
||||
ctx.arg.thinLTOJobs = v;
|
||||
}
|
||||
if (auto *arg = args.getLastArg(OPT_thinlto_jobs))
|
||||
config->thinLTOJobs = arg->getValue();
|
||||
ctx.arg.thinLTOJobs = arg->getValue();
|
||||
|
||||
if (auto *arg = args.getLastArg(OPT_features)) {
|
||||
config->features =
|
||||
ctx.arg.features =
|
||||
std::optional<std::vector<std::string>>(std::vector<std::string>());
|
||||
for (StringRef s : arg->getValues())
|
||||
config->features->push_back(std::string(s));
|
||||
ctx.arg.features->push_back(std::string(s));
|
||||
}
|
||||
|
||||
if (auto *arg = args.getLastArg(OPT_extra_features)) {
|
||||
config->extraFeatures =
|
||||
ctx.arg.extraFeatures =
|
||||
std::optional<std::vector<std::string>>(std::vector<std::string>());
|
||||
for (StringRef s : arg->getValues())
|
||||
config->extraFeatures->push_back(std::string(s));
|
||||
ctx.arg.extraFeatures->push_back(std::string(s));
|
||||
}
|
||||
|
||||
// Legacy --allow-undefined flag which is equivalent to
|
||||
// --unresolve-symbols=ignore + --import-undefined
|
||||
if (args.hasArg(OPT_allow_undefined)) {
|
||||
config->importUndefined = true;
|
||||
config->unresolvedSymbols = UnresolvedPolicy::Ignore;
|
||||
ctx.arg.importUndefined = true;
|
||||
ctx.arg.unresolvedSymbols = UnresolvedPolicy::Ignore;
|
||||
}
|
||||
|
||||
if (args.hasArg(OPT_print_map))
|
||||
config->mapFile = "-";
|
||||
ctx.arg.mapFile = "-";
|
||||
|
||||
std::tie(config->buildId, config->buildIdVector) = getBuildId(args);
|
||||
std::tie(ctx.arg.buildId, ctx.arg.buildIdVector) = getBuildId(args);
|
||||
}
|
||||
|
||||
// Some Config members do not directly correspond to any particular
|
||||
@@ -716,86 +714,86 @@ static void readConfigs(opt::InputArgList &args) {
|
||||
// This function initialize such members. See Config.h for the details
|
||||
// of these values.
|
||||
static void setConfigs() {
|
||||
ctx.isPic = config->pie || config->shared;
|
||||
ctx.isPic = ctx.arg.pie || ctx.arg.shared;
|
||||
|
||||
if (ctx.isPic) {
|
||||
if (config->exportTable)
|
||||
if (ctx.arg.exportTable)
|
||||
error("-shared/-pie is incompatible with --export-table");
|
||||
config->importTable = true;
|
||||
ctx.arg.importTable = true;
|
||||
} else {
|
||||
// Default table base. Defaults to 1, reserving 0 for the NULL function
|
||||
// pointer.
|
||||
if (!config->tableBase)
|
||||
config->tableBase = 1;
|
||||
if (!ctx.arg.tableBase)
|
||||
ctx.arg.tableBase = 1;
|
||||
// The default offset for static/global data, for when --global-base is
|
||||
// not specified on the command line. The precise value of 1024 is
|
||||
// somewhat arbitrary, and pre-dates wasm-ld (Its the value that
|
||||
// emscripten used prior to wasm-ld).
|
||||
if (!config->globalBase && !config->relocatable && !config->stackFirst)
|
||||
config->globalBase = 1024;
|
||||
if (!ctx.arg.globalBase && !ctx.arg.relocatable && !ctx.arg.stackFirst)
|
||||
ctx.arg.globalBase = 1024;
|
||||
}
|
||||
|
||||
if (config->relocatable) {
|
||||
if (config->exportTable)
|
||||
if (ctx.arg.relocatable) {
|
||||
if (ctx.arg.exportTable)
|
||||
error("--relocatable is incompatible with --export-table");
|
||||
if (config->growableTable)
|
||||
if (ctx.arg.growableTable)
|
||||
error("--relocatable is incompatible with --growable-table");
|
||||
// Ignore any --import-table, as it's redundant.
|
||||
config->importTable = true;
|
||||
ctx.arg.importTable = true;
|
||||
}
|
||||
|
||||
if (config->shared) {
|
||||
if (config->memoryExport.has_value()) {
|
||||
if (ctx.arg.shared) {
|
||||
if (ctx.arg.memoryExport.has_value()) {
|
||||
error("--export-memory is incompatible with --shared");
|
||||
}
|
||||
if (!config->memoryImport.has_value()) {
|
||||
config->memoryImport =
|
||||
std::pair<llvm::StringRef, llvm::StringRef>(defaultModule, memoryName);
|
||||
if (!ctx.arg.memoryImport.has_value()) {
|
||||
ctx.arg.memoryImport = std::pair<llvm::StringRef, llvm::StringRef>(
|
||||
defaultModule, memoryName);
|
||||
}
|
||||
}
|
||||
|
||||
// If neither export-memory nor import-memory is specified, default to
|
||||
// exporting memory under its default name.
|
||||
if (!config->memoryExport.has_value() && !config->memoryImport.has_value()) {
|
||||
config->memoryExport = memoryName;
|
||||
if (!ctx.arg.memoryExport.has_value() && !ctx.arg.memoryImport.has_value()) {
|
||||
ctx.arg.memoryExport = memoryName;
|
||||
}
|
||||
}
|
||||
|
||||
// Some command line options or some combinations of them are not allowed.
|
||||
// This function checks for such errors.
|
||||
static void checkOptions(opt::InputArgList &args) {
|
||||
if (!config->stripDebug && !config->stripAll && config->compressRelocations)
|
||||
if (!ctx.arg.stripDebug && !ctx.arg.stripAll && ctx.arg.compressRelocations)
|
||||
error("--compress-relocations is incompatible with output debug"
|
||||
" information. Please pass --strip-debug or --strip-all");
|
||||
|
||||
if (config->ltoPartitions == 0)
|
||||
if (ctx.arg.ltoPartitions == 0)
|
||||
error("--lto-partitions: number of threads must be > 0");
|
||||
if (!get_threadpool_strategy(config->thinLTOJobs))
|
||||
error("--thinlto-jobs: invalid job count: " + config->thinLTOJobs);
|
||||
if (!get_threadpool_strategy(ctx.arg.thinLTOJobs))
|
||||
error("--thinlto-jobs: invalid job count: " + ctx.arg.thinLTOJobs);
|
||||
|
||||
if (config->pie && config->shared)
|
||||
if (ctx.arg.pie && ctx.arg.shared)
|
||||
error("-shared and -pie may not be used together");
|
||||
|
||||
if (config->outputFile.empty() && !config->thinLTOIndexOnly)
|
||||
if (ctx.arg.outputFile.empty() && !ctx.arg.thinLTOIndexOnly)
|
||||
error("no output file specified");
|
||||
|
||||
if (config->importTable && config->exportTable)
|
||||
if (ctx.arg.importTable && ctx.arg.exportTable)
|
||||
error("--import-table and --export-table may not be used together");
|
||||
|
||||
if (config->relocatable) {
|
||||
if (!config->entry.empty())
|
||||
if (ctx.arg.relocatable) {
|
||||
if (!ctx.arg.entry.empty())
|
||||
error("entry point specified for relocatable output file");
|
||||
if (config->gcSections)
|
||||
if (ctx.arg.gcSections)
|
||||
error("-r and --gc-sections may not be used together");
|
||||
if (config->compressRelocations)
|
||||
if (ctx.arg.compressRelocations)
|
||||
error("-r -and --compress-relocations may not be used together");
|
||||
if (args.hasArg(OPT_undefined))
|
||||
error("-r -and --undefined may not be used together");
|
||||
if (config->pie)
|
||||
if (ctx.arg.pie)
|
||||
error("-r and -pie may not be used together");
|
||||
if (config->sharedMemory)
|
||||
if (ctx.arg.sharedMemory)
|
||||
error("-r and --shared-memory may not be used together");
|
||||
if (config->globalBase)
|
||||
if (ctx.arg.globalBase)
|
||||
error("-r and --global-base may not by used together");
|
||||
}
|
||||
|
||||
@@ -804,31 +802,31 @@ static void checkOptions(opt::InputArgList &args) {
|
||||
// mode, to give anyone using them a heads-up that they will be changing.
|
||||
//
|
||||
// Also, warn about flags which request explicit exports.
|
||||
if (!config->experimentalPic) {
|
||||
if (!ctx.arg.experimentalPic) {
|
||||
// -shared will change meaning when Module Linking is implemented.
|
||||
if (config->shared) {
|
||||
if (ctx.arg.shared) {
|
||||
warn("creating shared libraries, with -shared, is not yet stable");
|
||||
}
|
||||
|
||||
// -pie will change meaning when Module Linking is implemented.
|
||||
if (config->pie) {
|
||||
if (ctx.arg.pie) {
|
||||
warn("creating PIEs, with -pie, is not yet stable");
|
||||
}
|
||||
|
||||
if (config->unresolvedSymbols == UnresolvedPolicy::ImportDynamic) {
|
||||
if (ctx.arg.unresolvedSymbols == UnresolvedPolicy::ImportDynamic) {
|
||||
warn("dynamic imports are not yet stable "
|
||||
"(--unresolved-symbols=import-dynamic)");
|
||||
}
|
||||
}
|
||||
|
||||
if (config->bsymbolic && !config->shared) {
|
||||
if (ctx.arg.bsymbolic && !ctx.arg.shared) {
|
||||
warn("-Bsymbolic is only meaningful when combined with -shared");
|
||||
}
|
||||
|
||||
if (ctx.isPic) {
|
||||
if (config->globalBase)
|
||||
if (ctx.arg.globalBase)
|
||||
error("--global-base may not be used with -shared/-pie");
|
||||
if (config->tableBase)
|
||||
if (ctx.arg.tableBase)
|
||||
error("--table-base may not be used with -shared/-pie");
|
||||
}
|
||||
}
|
||||
@@ -851,7 +849,7 @@ static Symbol *handleUndefined(StringRef name, const char *option) {
|
||||
|
||||
if (auto *lazySym = dyn_cast<LazySymbol>(sym)) {
|
||||
lazySym->extract();
|
||||
if (!config->whyExtract.empty())
|
||||
if (!ctx.arg.whyExtract.empty())
|
||||
ctx.whyExtractRecords.emplace_back(option, sym->getFile(), *sym);
|
||||
}
|
||||
|
||||
@@ -861,20 +859,20 @@ static Symbol *handleUndefined(StringRef name, const char *option) {
|
||||
static void handleLibcall(StringRef name) {
|
||||
Symbol *sym = symtab->find(name);
|
||||
if (sym && sym->isLazy() && isa<BitcodeFile>(sym->getFile())) {
|
||||
if (!config->whyExtract.empty())
|
||||
if (!ctx.arg.whyExtract.empty())
|
||||
ctx.whyExtractRecords.emplace_back("<libcall>", sym->getFile(), *sym);
|
||||
cast<LazySymbol>(sym)->extract();
|
||||
}
|
||||
}
|
||||
|
||||
static void writeWhyExtract() {
|
||||
if (config->whyExtract.empty())
|
||||
if (ctx.arg.whyExtract.empty())
|
||||
return;
|
||||
|
||||
std::error_code ec;
|
||||
raw_fd_ostream os(config->whyExtract, ec, sys::fs::OF_None);
|
||||
raw_fd_ostream os(ctx.arg.whyExtract, ec, sys::fs::OF_None);
|
||||
if (ec) {
|
||||
error("cannot open --why-extract= file " + config->whyExtract + ": " +
|
||||
error("cannot open --why-extract= file " + ctx.arg.whyExtract + ": " +
|
||||
ec.message());
|
||||
return;
|
||||
}
|
||||
@@ -905,14 +903,14 @@ static UndefinedGlobal *
|
||||
createUndefinedGlobal(StringRef name, llvm::wasm::WasmGlobalType *type) {
|
||||
auto *sym = cast<UndefinedGlobal>(symtab->addUndefinedGlobal(
|
||||
name, std::nullopt, std::nullopt, WASM_SYMBOL_UNDEFINED, nullptr, type));
|
||||
config->allowUndefinedSymbols.insert(sym->getName());
|
||||
ctx.arg.allowUndefinedSymbols.insert(sym->getName());
|
||||
sym->isUsedInRegularObj = true;
|
||||
return sym;
|
||||
}
|
||||
|
||||
static InputGlobal *createGlobal(StringRef name, bool isMutable) {
|
||||
llvm::wasm::WasmGlobal wasmGlobal;
|
||||
bool is64 = config->is64.value_or(false);
|
||||
bool is64 = ctx.arg.is64.value_or(false);
|
||||
wasmGlobal.Type = {uint8_t(is64 ? WASM_TYPE_I64 : WASM_TYPE_I32), isMutable};
|
||||
wasmGlobal.InitExpr = intConst(0, is64);
|
||||
wasmGlobal.SymbolName = name;
|
||||
@@ -931,7 +929,7 @@ static GlobalSymbol *createOptionalGlobal(StringRef name, bool isMutable) {
|
||||
|
||||
// Create ABI-defined synthetic symbols
|
||||
static void createSyntheticSymbols() {
|
||||
if (config->relocatable)
|
||||
if (ctx.arg.relocatable)
|
||||
return;
|
||||
|
||||
static WasmSignature nullSignature = {{}, {}};
|
||||
@@ -947,11 +945,11 @@ static void createSyntheticSymbols() {
|
||||
"__wasm_call_ctors", WASM_SYMBOL_VISIBILITY_HIDDEN,
|
||||
make<SyntheticFunction>(nullSignature, "__wasm_call_ctors"));
|
||||
|
||||
bool is64 = config->is64.value_or(false);
|
||||
bool is64 = ctx.arg.is64.value_or(false);
|
||||
|
||||
if (ctx.isPic) {
|
||||
WasmSym::stackPointer =
|
||||
createUndefinedGlobal("__stack_pointer", config->is64.value_or(false)
|
||||
createUndefinedGlobal("__stack_pointer", ctx.arg.is64.value_or(false)
|
||||
? &mutableGlobalTypeI64
|
||||
: &mutableGlobalTypeI32);
|
||||
// For PIC code, we import two global variables (__memory_base and
|
||||
@@ -970,7 +968,7 @@ static void createSyntheticSymbols() {
|
||||
WasmSym::stackPointer->markLive();
|
||||
}
|
||||
|
||||
if (config->sharedMemory) {
|
||||
if (ctx.arg.sharedMemory) {
|
||||
WasmSym::tlsBase = createGlobalVariable("__tls_base", true);
|
||||
WasmSym::tlsSize = createGlobalVariable("__tls_size", false);
|
||||
WasmSym::tlsAlign = createGlobalVariable("__tls_align", false);
|
||||
@@ -983,12 +981,12 @@ static void createSyntheticSymbols() {
|
||||
}
|
||||
|
||||
static void createOptionalSymbols() {
|
||||
if (config->relocatable)
|
||||
if (ctx.arg.relocatable)
|
||||
return;
|
||||
|
||||
WasmSym::dsoHandle = symtab->addOptionalDataSymbol("__dso_handle");
|
||||
|
||||
if (!config->shared)
|
||||
if (!ctx.arg.shared)
|
||||
WasmSym::dataEnd = symtab->addOptionalDataSymbol("__data_end");
|
||||
|
||||
if (!ctx.isPic) {
|
||||
@@ -1010,7 +1008,7 @@ static void createOptionalSymbols() {
|
||||
//
|
||||
// __tls_size and __tls_align are not needed in this case since they are only
|
||||
// needed for __wasm_init_tls (which we do not create in this case).
|
||||
if (!config->sharedMemory)
|
||||
if (!ctx.arg.sharedMemory)
|
||||
WasmSym::tlsBase = createOptionalGlobal("__tls_base", false);
|
||||
}
|
||||
|
||||
@@ -1035,7 +1033,7 @@ static void processStubLibrariesPreLTO() {
|
||||
// extracted during processStubLibraries, which is too late since
|
||||
// LTO has already being performed at that point.
|
||||
if (needed->isLazy() && isa<BitcodeFile>(needed->getFile())) {
|
||||
if (!config->whyExtract.empty())
|
||||
if (!ctx.arg.whyExtract.empty())
|
||||
ctx.whyExtractRecords.emplace_back(toString(stub_file),
|
||||
needed->getFile(), *needed);
|
||||
cast<LazySymbol>(needed)->extract();
|
||||
@@ -1079,7 +1077,7 @@ static bool addStubSymbolDeps(const StubFile *stub_file, Symbol *sym,
|
||||
if (auto *lazy = dyn_cast<LazySymbol>(needed)) {
|
||||
depsAdded = true;
|
||||
lazy->extract();
|
||||
if (!config->whyExtract.empty())
|
||||
if (!ctx.arg.whyExtract.empty())
|
||||
ctx.whyExtractRecords.emplace_back(toString(stub_file),
|
||||
sym->getFile(), *sym);
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ uint32_t InputChunk::getSize() const {
|
||||
return ms->builder.getSize();
|
||||
|
||||
if (const auto *f = dyn_cast<InputFunction>(this)) {
|
||||
if (config->compressRelocations && f->file) {
|
||||
if (ctx.arg.compressRelocations && f->file) {
|
||||
return f->getCompressedSize();
|
||||
}
|
||||
}
|
||||
@@ -84,7 +84,7 @@ uint32_t InputChunk::getInputSize() const {
|
||||
// Copy this input chunk to an mmap'ed output file and apply relocations.
|
||||
void InputChunk::writeTo(uint8_t *buf) const {
|
||||
if (const auto *f = dyn_cast<InputFunction>(this)) {
|
||||
if (file && config->compressRelocations)
|
||||
if (file && ctx.arg.compressRelocations)
|
||||
return f->writeCompressed(buf);
|
||||
} else if (const auto *ms = dyn_cast<SyntheticMergedChunk>(this)) {
|
||||
ms->builder.write(buf + outSecOff);
|
||||
@@ -269,7 +269,7 @@ static unsigned getRelocWidth(const WasmRelocation &rel, uint64_t value) {
|
||||
// This function only computes the final output size. It must be called
|
||||
// before getSize() is used to calculate of layout of the code section.
|
||||
void InputFunction::calculateSize() {
|
||||
if (!file || !config->compressRelocations)
|
||||
if (!file || !ctx.arg.compressRelocations)
|
||||
return;
|
||||
|
||||
LLVM_DEBUG(dbgs() << "calculateSize: " << name << "\n");
|
||||
@@ -365,7 +365,7 @@ bool InputChunk::generateRelocationCode(raw_ostream &os) const {
|
||||
LLVM_DEBUG(dbgs() << "generating runtime relocations: " << name
|
||||
<< " count=" << relocations.size() << "\n");
|
||||
|
||||
bool is64 = config->is64.value_or(false);
|
||||
bool is64 = ctx.arg.is64.value_or(false);
|
||||
bool generated = false;
|
||||
unsigned opcode_ptr_const = is64 ? WASM_OPCODE_I64_CONST
|
||||
: WASM_OPCODE_I32_CONST;
|
||||
|
||||
@@ -112,7 +112,7 @@ protected:
|
||||
InputChunk(ObjFile *f, Kind k, StringRef name, uint32_t alignment = 0,
|
||||
uint32_t flags = 0)
|
||||
: name(name), file(f), alignment(alignment), flags(flags), sectionKind(k),
|
||||
live(!config->gcSections), discarded(false) {}
|
||||
live(!ctx.arg.gcSections), discarded(false) {}
|
||||
ArrayRef<uint8_t> data() const { return rawData; }
|
||||
uint64_t getTombstone() const;
|
||||
|
||||
@@ -156,7 +156,7 @@ class SyntheticMergedChunk;
|
||||
// be found by looking at the next one).
|
||||
struct SectionPiece {
|
||||
SectionPiece(size_t off, uint32_t hash, bool live)
|
||||
: inputOff(off), live(live || !config->gcSections), hash(hash >> 1) {}
|
||||
: inputOff(off), live(live || !ctx.arg.gcSections), hash(hash >> 1) {}
|
||||
|
||||
uint32_t inputOff;
|
||||
uint32_t live : 1;
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace wasm {
|
||||
class InputElement {
|
||||
protected:
|
||||
InputElement(StringRef name, ObjFile *f)
|
||||
: file(f), live(!config->gcSections), name(name) {}
|
||||
: file(f), live(!ctx.arg.gcSections), name(name) {}
|
||||
|
||||
public:
|
||||
StringRef getName() const { return name; }
|
||||
@@ -65,7 +65,7 @@ public:
|
||||
const WasmInitExpr &getInitExpr() const { return initExpr; }
|
||||
|
||||
void setPointerValue(uint64_t value) {
|
||||
initExpr = intConst(value, config->is64.value_or(false));
|
||||
initExpr = intConst(value, ctx.arg.is64.value_or(false));
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -47,7 +47,7 @@ std::string toString(const wasm::InputFile *file) {
|
||||
namespace wasm {
|
||||
|
||||
std::string replaceThinLTOSuffix(StringRef path) {
|
||||
auto [suffix, repl] = config->thinLTOObjectSuffixReplace;
|
||||
auto [suffix, repl] = ctx.arg.thinLTOObjectSuffixReplace;
|
||||
if (path.consume_back(suffix))
|
||||
return (path + repl).str();
|
||||
return std::string(path);
|
||||
@@ -55,10 +55,10 @@ std::string replaceThinLTOSuffix(StringRef path) {
|
||||
|
||||
void InputFile::checkArch(Triple::ArchType arch) const {
|
||||
bool is64 = arch == Triple::wasm64;
|
||||
if (is64 && !config->is64) {
|
||||
if (is64 && !ctx.arg.is64) {
|
||||
fatal(toString(this) +
|
||||
": must specify -mwasm64 to process wasm64 object files");
|
||||
} else if (config->is64.value_or(false) != is64) {
|
||||
} else if (ctx.arg.is64.value_or(false) != is64) {
|
||||
fatal(toString(this) +
|
||||
": wasm32 object file can't be linked in wasm64 mode");
|
||||
}
|
||||
@@ -169,7 +169,7 @@ uint64_t ObjFile::calcNewValue(const WasmRelocation &reloc, uint64_t tombstone,
|
||||
uint32_t index = getFunctionSymbol(reloc.Index)->getTableIndex();
|
||||
if (reloc.Type == R_WASM_TABLE_INDEX_REL_SLEB ||
|
||||
reloc.Type == R_WASM_TABLE_INDEX_REL_SLEB64)
|
||||
index -= config->tableBase;
|
||||
index -= ctx.arg.tableBase;
|
||||
return index;
|
||||
}
|
||||
case R_WASM_MEMORY_ADDR_LEB:
|
||||
@@ -360,7 +360,7 @@ void ObjFile::addLegacyIndirectFunctionTableIfNeeded(
|
||||
}
|
||||
|
||||
static bool shouldMerge(const WasmSection &sec) {
|
||||
if (config->optimize == 0)
|
||||
if (ctx.arg.optimize == 0)
|
||||
return false;
|
||||
// Sadly we don't have section attributes yet for custom sections, so we
|
||||
// currently go by the name alone.
|
||||
@@ -383,7 +383,7 @@ static bool shouldMerge(const WasmSegment &seg) {
|
||||
// On a regular link we don't merge sections if -O0 (default is -O1). This
|
||||
// sometimes makes the linker significantly faster, although the output will
|
||||
// be bigger.
|
||||
if (config->optimize == 0)
|
||||
if (ctx.arg.optimize == 0)
|
||||
return false;
|
||||
|
||||
// A mergeable section with size 0 is useless because they don't have
|
||||
@@ -845,7 +845,7 @@ BitcodeFile::BitcodeFile(MemoryBufferRef m, StringRef archiveName,
|
||||
this->archiveName = std::string(archiveName);
|
||||
|
||||
std::string path = mb.getBufferIdentifier().str();
|
||||
if (config->thinLTOIndexOnly)
|
||||
if (ctx.arg.thinLTOIndexOnly)
|
||||
path = replaceThinLTOSuffix(mb.getBufferIdentifier());
|
||||
|
||||
// ThinLTO assumes that all MemoryBufferRefs given to it have a unique
|
||||
|
||||
@@ -73,7 +73,7 @@ public:
|
||||
|
||||
protected:
|
||||
InputFile(Kind k, MemoryBufferRef m)
|
||||
: mb(m), fileKind(k), live(!config->gcSections) {}
|
||||
: mb(m), fileKind(k), live(!ctx.arg.gcSections) {}
|
||||
|
||||
void checkArch(llvm::Triple::ArchType arch) const;
|
||||
|
||||
|
||||
@@ -44,8 +44,8 @@ using namespace lld::wasm;
|
||||
using namespace lld;
|
||||
|
||||
static std::string getThinLTOOutputFile(StringRef modulePath) {
|
||||
return lto::getThinLTOOutputFile(modulePath, config->thinLTOPrefixReplaceOld,
|
||||
config->thinLTOPrefixReplaceNew);
|
||||
return lto::getThinLTOOutputFile(modulePath, ctx.arg.thinLTOPrefixReplaceOld,
|
||||
ctx.arg.thinLTOPrefixReplaceNew);
|
||||
}
|
||||
|
||||
static lto::Config createConfig() {
|
||||
@@ -56,23 +56,23 @@ static lto::Config createConfig() {
|
||||
c.Options.FunctionSections = true;
|
||||
c.Options.DataSections = true;
|
||||
|
||||
c.DisableVerify = config->disableVerify;
|
||||
c.DisableVerify = ctx.arg.disableVerify;
|
||||
c.DiagHandler = diagnosticHandler;
|
||||
c.OptLevel = config->ltoo;
|
||||
c.OptLevel = ctx.arg.ltoo;
|
||||
c.MAttrs = getMAttrs();
|
||||
c.CGOptLevel = config->ltoCgo;
|
||||
c.DebugPassManager = config->ltoDebugPassManager;
|
||||
c.AlwaysEmitRegularLTOObj = !config->ltoObjPath.empty();
|
||||
c.CGOptLevel = ctx.arg.ltoCgo;
|
||||
c.DebugPassManager = ctx.arg.ltoDebugPassManager;
|
||||
c.AlwaysEmitRegularLTOObj = !ctx.arg.ltoObjPath.empty();
|
||||
|
||||
if (config->relocatable)
|
||||
if (ctx.arg.relocatable)
|
||||
c.RelocModel = std::nullopt;
|
||||
else if (ctx.isPic)
|
||||
c.RelocModel = Reloc::PIC_;
|
||||
else
|
||||
c.RelocModel = Reloc::Static;
|
||||
|
||||
if (config->saveTemps)
|
||||
checkError(c.addSaveTemps(config->outputFile.str() + ".",
|
||||
if (ctx.arg.saveTemps)
|
||||
checkError(c.addSaveTemps(ctx.arg.outputFile.str() + ".",
|
||||
/*UseInputModulePath*/ true));
|
||||
return c;
|
||||
}
|
||||
@@ -81,27 +81,27 @@ namespace lld::wasm {
|
||||
|
||||
BitcodeCompiler::BitcodeCompiler() {
|
||||
// Initialize indexFile.
|
||||
if (!config->thinLTOIndexOnlyArg.empty())
|
||||
indexFile = openFile(config->thinLTOIndexOnlyArg);
|
||||
if (!ctx.arg.thinLTOIndexOnlyArg.empty())
|
||||
indexFile = openFile(ctx.arg.thinLTOIndexOnlyArg);
|
||||
|
||||
// Initialize ltoObj.
|
||||
lto::ThinBackend backend;
|
||||
auto onIndexWrite = [&](StringRef s) { thinIndices.erase(s); };
|
||||
if (config->thinLTOIndexOnly) {
|
||||
if (ctx.arg.thinLTOIndexOnly) {
|
||||
backend = lto::createWriteIndexesThinBackend(
|
||||
llvm::hardware_concurrency(config->thinLTOJobs),
|
||||
std::string(config->thinLTOPrefixReplaceOld),
|
||||
std::string(config->thinLTOPrefixReplaceNew),
|
||||
std::string(config->thinLTOPrefixReplaceNativeObject),
|
||||
config->thinLTOEmitImportsFiles, indexFile.get(), onIndexWrite);
|
||||
llvm::hardware_concurrency(ctx.arg.thinLTOJobs),
|
||||
std::string(ctx.arg.thinLTOPrefixReplaceOld),
|
||||
std::string(ctx.arg.thinLTOPrefixReplaceNew),
|
||||
std::string(ctx.arg.thinLTOPrefixReplaceNativeObject),
|
||||
ctx.arg.thinLTOEmitImportsFiles, indexFile.get(), onIndexWrite);
|
||||
} else {
|
||||
backend = lto::createInProcessThinBackend(
|
||||
llvm::heavyweight_hardware_concurrency(config->thinLTOJobs),
|
||||
onIndexWrite, config->thinLTOEmitIndexFiles,
|
||||
config->thinLTOEmitImportsFiles);
|
||||
llvm::heavyweight_hardware_concurrency(ctx.arg.thinLTOJobs),
|
||||
onIndexWrite, ctx.arg.thinLTOEmitIndexFiles,
|
||||
ctx.arg.thinLTOEmitImportsFiles);
|
||||
}
|
||||
ltoObj = std::make_unique<lto::LTO>(createConfig(), backend,
|
||||
config->ltoPartitions);
|
||||
ctx.arg.ltoPartitions);
|
||||
}
|
||||
|
||||
BitcodeCompiler::~BitcodeCompiler() = default;
|
||||
@@ -123,7 +123,7 @@ void BitcodeCompiler::add(BitcodeFile &f) {
|
||||
ArrayRef<Symbol *> syms = f.getSymbols();
|
||||
std::vector<lto::SymbolResolution> resols(syms.size());
|
||||
|
||||
if (config->thinLTOEmitIndexFiles) {
|
||||
if (ctx.arg.thinLTOEmitIndexFiles) {
|
||||
thinIndices.insert(obj.getName());
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ void BitcodeCompiler::add(BitcodeFile &f) {
|
||||
// Once IRObjectFile is fixed to report only one symbol this hack can
|
||||
// be removed.
|
||||
r.Prevailing = !objSym.isUndefined() && sym->getFile() == &f;
|
||||
r.VisibleToRegularObj = config->relocatable || sym->isUsedInRegularObj ||
|
||||
r.VisibleToRegularObj = ctx.arg.relocatable || sym->isUsedInRegularObj ||
|
||||
sym->isNoStrip() ||
|
||||
(r.Prevailing && sym->isExported());
|
||||
if (r.Prevailing)
|
||||
@@ -175,7 +175,7 @@ static void thinLTOCreateEmptyIndexFiles() {
|
||||
ModuleSummaryIndex m(/*HaveGVs*/ false);
|
||||
m.setSkipModuleByDistributedBackend();
|
||||
writeIndexToFile(m, *os);
|
||||
if (config->thinLTOEmitImportsFiles)
|
||||
if (ctx.arg.thinLTOEmitImportsFiles)
|
||||
openFile(path + ".imports");
|
||||
}
|
||||
}
|
||||
@@ -191,8 +191,8 @@ std::vector<StringRef> BitcodeCompiler::compile() {
|
||||
// to cache native object files for ThinLTO incremental builds. If a path was
|
||||
// specified, configure LTO to use it as the cache directory.
|
||||
FileCache cache;
|
||||
if (!config->thinLTOCacheDir.empty())
|
||||
cache = check(localCache("ThinLTO", "Thin", config->thinLTOCacheDir,
|
||||
if (!ctx.arg.thinLTOCacheDir.empty())
|
||||
cache = check(localCache("ThinLTO", "Thin", ctx.arg.thinLTOCacheDir,
|
||||
[&](size_t task, const Twine &moduleName,
|
||||
std::unique_ptr<MemoryBuffer> mb) {
|
||||
files[task] = std::move(mb);
|
||||
@@ -210,16 +210,16 @@ std::vector<StringRef> BitcodeCompiler::compile() {
|
||||
for (StringRef s : thinIndices) {
|
||||
std::string path(s);
|
||||
openFile(path + ".thinlto.bc");
|
||||
if (config->thinLTOEmitImportsFiles)
|
||||
if (ctx.arg.thinLTOEmitImportsFiles)
|
||||
openFile(path + ".imports");
|
||||
}
|
||||
|
||||
if (config->thinLTOEmitIndexFiles)
|
||||
if (ctx.arg.thinLTOEmitIndexFiles)
|
||||
thinLTOCreateEmptyIndexFiles();
|
||||
|
||||
if (config->thinLTOIndexOnly) {
|
||||
if (!config->ltoObjPath.empty())
|
||||
saveBuffer(buf[0].second, config->ltoObjPath);
|
||||
if (ctx.arg.thinLTOIndexOnly) {
|
||||
if (!ctx.arg.ltoObjPath.empty())
|
||||
saveBuffer(buf[0].second, ctx.arg.ltoObjPath);
|
||||
|
||||
// ThinLTO with index only option is required to generate only the index
|
||||
// files. After that, we exit from linker and ThinLTO backend runs in a
|
||||
@@ -229,8 +229,8 @@ std::vector<StringRef> BitcodeCompiler::compile() {
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!config->thinLTOCacheDir.empty())
|
||||
pruneCache(config->thinLTOCacheDir, config->thinLTOCachePolicy, files);
|
||||
if (!ctx.arg.thinLTOCacheDir.empty())
|
||||
pruneCache(ctx.arg.thinLTOCacheDir, ctx.arg.thinLTOCachePolicy, files);
|
||||
|
||||
std::vector<StringRef> ret;
|
||||
for (unsigned i = 0; i != maxTasks; ++i) {
|
||||
@@ -239,7 +239,7 @@ std::vector<StringRef> BitcodeCompiler::compile() {
|
||||
if (objBuf.empty())
|
||||
continue;
|
||||
ret.emplace_back(objBuf.data(), objBuf.size());
|
||||
if (!config->saveTemps)
|
||||
if (!ctx.arg.saveTemps)
|
||||
continue;
|
||||
|
||||
// If the input bitcode file is path/to/x.o and -o specifies a.out, the
|
||||
@@ -248,7 +248,7 @@ std::vector<StringRef> BitcodeCompiler::compile() {
|
||||
StringRef ltoObjName;
|
||||
if (bitcodeFilePath == "ld-temp.o") {
|
||||
ltoObjName =
|
||||
saver().save(Twine(config->outputFile) + ".lto" +
|
||||
saver().save(Twine(ctx.arg.outputFile) + ".lto" +
|
||||
(i == 0 ? Twine("") : Twine('.') + Twine(i)) + ".o");
|
||||
} else {
|
||||
StringRef directory = sys::path::parent_path(bitcodeFilePath);
|
||||
@@ -258,7 +258,7 @@ std::vector<StringRef> BitcodeCompiler::compile() {
|
||||
StringRef baseName = bitcodeFilePath.ends_with(")")
|
||||
? sys::path::filename(bitcodeFilePath)
|
||||
: sys::path::stem(bitcodeFilePath);
|
||||
StringRef outputFileBaseName = sys::path::filename(config->outputFile);
|
||||
StringRef outputFileBaseName = sys::path::filename(ctx.arg.outputFile);
|
||||
SmallString<256> path;
|
||||
sys::path::append(path, directory,
|
||||
outputFileBaseName + ".lto." + baseName + ".o");
|
||||
@@ -268,10 +268,10 @@ std::vector<StringRef> BitcodeCompiler::compile() {
|
||||
saveBuffer(objBuf, ltoObjName);
|
||||
}
|
||||
|
||||
if (!config->ltoObjPath.empty()) {
|
||||
saveBuffer(buf[0].second, config->ltoObjPath);
|
||||
if (!ctx.arg.ltoObjPath.empty()) {
|
||||
saveBuffer(buf[0].second, ctx.arg.ltoObjPath);
|
||||
for (unsigned i = 1; i != maxTasks; ++i)
|
||||
saveBuffer(buf[i].second, config->ltoObjPath + Twine(i));
|
||||
saveBuffer(buf[i].second, ctx.arg.ltoObjPath + Twine(i));
|
||||
}
|
||||
|
||||
for (std::unique_ptr<MemoryBuffer> &file : files)
|
||||
|
||||
@@ -103,14 +103,14 @@ getSymbolStrings(ArrayRef<Symbol *> syms) {
|
||||
}
|
||||
|
||||
void lld::wasm::writeMapFile(ArrayRef<OutputSection *> outputSections) {
|
||||
if (config->mapFile.empty())
|
||||
if (ctx.arg.mapFile.empty())
|
||||
return;
|
||||
|
||||
// Open a map file for writing.
|
||||
std::error_code ec;
|
||||
raw_fd_ostream os(config->mapFile, ec, sys::fs::OF_None);
|
||||
raw_fd_ostream os(ctx.arg.mapFile, ec, sys::fs::OF_None);
|
||||
if (ec) {
|
||||
error("cannot open " + config->mapFile + ": " + ec.message());
|
||||
error("cannot open " + ctx.arg.mapFile + ": " + ec.message());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -106,8 +106,8 @@ void MarkLive::enqueueRetainedSegments(const ObjFile *file) {
|
||||
|
||||
void MarkLive::run() {
|
||||
// Add GC root symbols.
|
||||
if (!config->entry.empty())
|
||||
enqueue(symtab->find(config->entry));
|
||||
if (!ctx.arg.entry.empty())
|
||||
enqueue(symtab->find(ctx.arg.entry));
|
||||
|
||||
// We need to preserve any no-strip or exported symbol
|
||||
for (Symbol *sym : symtab->symbols())
|
||||
@@ -166,7 +166,7 @@ void MarkLive::mark() {
|
||||
}
|
||||
|
||||
void markLive() {
|
||||
if (!config->gcSections)
|
||||
if (!ctx.arg.gcSections)
|
||||
return;
|
||||
|
||||
LLVM_DEBUG(dbgs() << "markLive\n");
|
||||
@@ -175,7 +175,7 @@ void markLive() {
|
||||
marker.run();
|
||||
|
||||
// Report garbage-collected sections.
|
||||
if (config->printGcSections) {
|
||||
if (ctx.arg.printGcSections) {
|
||||
for (const ObjFile *obj : ctx.objectFiles) {
|
||||
for (InputChunk *c : obj->functions)
|
||||
if (!c->live)
|
||||
@@ -207,7 +207,7 @@ void markLive() {
|
||||
|
||||
bool MarkLive::isCallCtorsLive() {
|
||||
// In a reloctable link, we don't call `__wasm_call_ctors`.
|
||||
if (config->relocatable)
|
||||
if (ctx.arg.relocatable)
|
||||
return false;
|
||||
|
||||
// In Emscripten-style PIC, we call `__wasm_call_ctors` which calls
|
||||
|
||||
@@ -105,13 +105,13 @@ void DataSection::finalizeContents() {
|
||||
});
|
||||
#endif
|
||||
|
||||
assert((config->sharedMemory || !ctx.isPic || config->extendedConst ||
|
||||
assert((ctx.arg.sharedMemory || !ctx.isPic || ctx.arg.extendedConst ||
|
||||
activeCount <= 1) &&
|
||||
"output segments should have been combined by now");
|
||||
|
||||
writeUleb128(os, segmentCount, "data segment count");
|
||||
bodySize = dataSectionHeader.size();
|
||||
bool is64 = config->is64.value_or(false);
|
||||
bool is64 = ctx.arg.is64.value_or(false);
|
||||
|
||||
for (OutputSegment *segment : segments) {
|
||||
if (!segment->requiredInBinary())
|
||||
@@ -121,7 +121,7 @@ void DataSection::finalizeContents() {
|
||||
if (segment->initFlags & WASM_DATA_SEGMENT_HAS_MEMINDEX)
|
||||
writeUleb128(os, 0, "memory index");
|
||||
if ((segment->initFlags & WASM_DATA_SEGMENT_IS_PASSIVE) == 0) {
|
||||
if (ctx.isPic && config->extendedConst) {
|
||||
if (ctx.isPic && ctx.arg.extendedConst) {
|
||||
writeU8(os, WASM_OPCODE_GLOBAL_GET, "global get");
|
||||
writeUleb128(os, WasmSym::memoryBase->getGlobalIndex(),
|
||||
"literal (global index)");
|
||||
|
||||
@@ -22,13 +22,13 @@ static bool requiresGOTAccess(const Symbol *sym) {
|
||||
if (sym->isShared())
|
||||
return true;
|
||||
if (!ctx.isPic &&
|
||||
config->unresolvedSymbols != UnresolvedPolicy::ImportDynamic)
|
||||
ctx.arg.unresolvedSymbols != UnresolvedPolicy::ImportDynamic)
|
||||
return false;
|
||||
if (sym->isHidden() || sym->isLocal())
|
||||
return false;
|
||||
// With `-Bsymbolic` (or when building an executable) as don't need to use
|
||||
// the GOT for symbols that are defined within the current module.
|
||||
if (sym->isDefined() && (!config->shared || config->bsymbolic))
|
||||
if (sym->isDefined() && (!ctx.arg.shared || ctx.arg.bsymbolic))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
@@ -38,15 +38,15 @@ static bool allowUndefined(const Symbol* sym) {
|
||||
// link time.
|
||||
if (sym->isImported())
|
||||
return true;
|
||||
if (isa<UndefinedFunction>(sym) && config->importUndefined)
|
||||
if (isa<UndefinedFunction>(sym) && ctx.arg.importUndefined)
|
||||
return true;
|
||||
|
||||
return config->allowUndefinedSymbols.count(sym->getName()) != 0;
|
||||
return ctx.arg.allowUndefinedSymbols.count(sym->getName()) != 0;
|
||||
}
|
||||
|
||||
static void reportUndefined(ObjFile *file, Symbol *sym) {
|
||||
if (!allowUndefined(sym)) {
|
||||
switch (config->unresolvedSymbols) {
|
||||
switch (ctx.arg.unresolvedSymbols) {
|
||||
case UnresolvedPolicy::ReportError:
|
||||
error(toString(file) + ": undefined symbol: " + toString(*sym));
|
||||
break;
|
||||
@@ -63,8 +63,8 @@ static void reportUndefined(ObjFile *file, Symbol *sym) {
|
||||
|
||||
if (auto *f = dyn_cast<UndefinedFunction>(sym)) {
|
||||
if (!f->stubFunction &&
|
||||
config->unresolvedSymbols != UnresolvedPolicy::ImportDynamic &&
|
||||
!config->importUndefined) {
|
||||
ctx.arg.unresolvedSymbols != UnresolvedPolicy::ImportDynamic &&
|
||||
!ctx.arg.importUndefined) {
|
||||
f->stubFunction = symtab->createUndefinedStub(*f->getSignature());
|
||||
f->stubFunction->markLive();
|
||||
// Mark the function itself as a stub which prevents it from being
|
||||
@@ -125,7 +125,7 @@ void scanRelocations(InputChunk *chunk) {
|
||||
// In single-threaded builds TLS is lowered away and TLS data can be
|
||||
// merged with normal data and allowing TLS relocation in non-TLS
|
||||
// segments.
|
||||
if (config->sharedMemory) {
|
||||
if (ctx.arg.sharedMemory) {
|
||||
if (!sym->isTLS()) {
|
||||
error(toString(file) + ": relocation " +
|
||||
relocTypeToString(reloc.Type) +
|
||||
@@ -146,7 +146,7 @@ void scanRelocations(InputChunk *chunk) {
|
||||
|
||||
if (ctx.isPic ||
|
||||
(sym->isUndefined() &&
|
||||
config->unresolvedSymbols == UnresolvedPolicy::ImportDynamic)) {
|
||||
ctx.arg.unresolvedSymbols == UnresolvedPolicy::ImportDynamic)) {
|
||||
switch (reloc.Type) {
|
||||
case R_WASM_TABLE_INDEX_SLEB:
|
||||
case R_WASM_TABLE_INDEX_SLEB64:
|
||||
@@ -173,7 +173,7 @@ void scanRelocations(InputChunk *chunk) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!config->relocatable && sym->isUndefined()) {
|
||||
if (!ctx.arg.relocatable && sym->isUndefined()) {
|
||||
switch (reloc.Type) {
|
||||
case R_WASM_TABLE_INDEX_REL_SLEB:
|
||||
case R_WASM_TABLE_INDEX_REL_SLEB64:
|
||||
|
||||
@@ -53,7 +53,7 @@ void SymbolTable::addFile(InputFile *file, StringRef symName) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (config->trace)
|
||||
if (ctx.arg.trace)
|
||||
message(toString(file));
|
||||
|
||||
// LLVM bitcode file
|
||||
@@ -125,7 +125,7 @@ std::pair<Symbol *, bool> SymbolTable::insertName(StringRef name) {
|
||||
sym->canInline = true;
|
||||
sym->traced = trace;
|
||||
sym->forceExport = false;
|
||||
sym->referenced = !config->gcSections;
|
||||
sym->referenced = !ctx.arg.gcSections;
|
||||
symVector.emplace_back(sym);
|
||||
return {sym, true};
|
||||
}
|
||||
@@ -235,7 +235,7 @@ DefinedFunction *SymbolTable::addSyntheticFunction(StringRef name,
|
||||
DefinedData *SymbolTable::addOptionalDataSymbol(StringRef name,
|
||||
uint64_t value) {
|
||||
Symbol *s = find(name);
|
||||
if (!s && (config->exportAll || config->exportedSymbols.count(name) != 0))
|
||||
if (!s && (ctx.arg.exportAll || ctx.arg.exportedSymbols.count(name) != 0))
|
||||
s = insertName(name).first;
|
||||
else if (!s || s->isDefined())
|
||||
return nullptr;
|
||||
@@ -317,7 +317,7 @@ static bool shouldReplace(const Symbol *existing, InputFile *newFile,
|
||||
}
|
||||
|
||||
// Neither symbol is week. They conflict.
|
||||
if (config->allowMultipleDefinition)
|
||||
if (ctx.arg.allowMultipleDefinition)
|
||||
return false;
|
||||
|
||||
errorOrWarn("duplicate symbol: " + toString(*existing) + "\n>>> defined in " +
|
||||
@@ -387,7 +387,7 @@ Symbol *SymbolTable::addSharedFunction(StringRef name, uint32_t flags,
|
||||
checkSig = ud->isCalledDirectly;
|
||||
|
||||
if (checkSig && !signatureMatches(existingFunction, sig)) {
|
||||
if (config->shlibSigCheck) {
|
||||
if (ctx.arg.shlibSigCheck) {
|
||||
reportFunctionSignatureMismatch(name, existingFunction, sig, file);
|
||||
} else {
|
||||
// With --no-shlib-sigcheck we ignore the signature of the function as
|
||||
@@ -637,7 +637,7 @@ Symbol *SymbolTable::addUndefinedFunction(StringRef name,
|
||||
lazy->signature = sig;
|
||||
} else {
|
||||
lazy->extract();
|
||||
if (!config->whyExtract.empty())
|
||||
if (!ctx.arg.whyExtract.empty())
|
||||
ctx.whyExtractRecords.emplace_back(toString(file), s->getFile(), *s);
|
||||
}
|
||||
} else {
|
||||
@@ -652,7 +652,7 @@ Symbol *SymbolTable::addUndefinedFunction(StringRef name,
|
||||
if (isCalledDirectly && !signatureMatches(existingFunction, sig)) {
|
||||
if (existingFunction->isShared()) {
|
||||
// Special handling for when the existing function is a shared symbol
|
||||
if (config->shlibSigCheck) {
|
||||
if (ctx.arg.shlibSigCheck) {
|
||||
reportFunctionSignatureMismatch(name, existingFunction, sig, file);
|
||||
} else {
|
||||
existingFunction->signature = sig;
|
||||
@@ -788,12 +788,12 @@ TableSymbol *SymbolTable::createUndefinedIndirectFunctionTable(StringRef name) {
|
||||
WasmTableType *type = make<WasmTableType>();
|
||||
type->ElemType = ValType::FUNCREF;
|
||||
type->Limits = limits;
|
||||
uint32_t flags = config->exportTable ? 0 : WASM_SYMBOL_VISIBILITY_HIDDEN;
|
||||
uint32_t flags = ctx.arg.exportTable ? 0 : WASM_SYMBOL_VISIBILITY_HIDDEN;
|
||||
flags |= WASM_SYMBOL_UNDEFINED;
|
||||
Symbol *sym =
|
||||
addUndefinedTable(name, name, defaultModule, flags, nullptr, type);
|
||||
sym->markLive();
|
||||
sym->forceExport = config->exportTable;
|
||||
sym->forceExport = ctx.arg.exportTable;
|
||||
return cast<TableSymbol>(sym);
|
||||
}
|
||||
|
||||
@@ -803,10 +803,10 @@ TableSymbol *SymbolTable::createDefinedIndirectFunctionTable(StringRef name) {
|
||||
WasmTableType type{ValType::FUNCREF, limits};
|
||||
WasmTable desc{invalidIndex, type, name};
|
||||
InputTable *table = make<InputTable>(desc, nullptr);
|
||||
uint32_t flags = config->exportTable ? 0 : WASM_SYMBOL_VISIBILITY_HIDDEN;
|
||||
uint32_t flags = ctx.arg.exportTable ? 0 : WASM_SYMBOL_VISIBILITY_HIDDEN;
|
||||
TableSymbol *sym = addSyntheticTable(name, flags, table);
|
||||
sym->markLive();
|
||||
sym->forceExport = config->exportTable;
|
||||
sym->forceExport = ctx.arg.exportTable;
|
||||
return sym;
|
||||
}
|
||||
|
||||
@@ -830,7 +830,7 @@ TableSymbol *SymbolTable::resolveIndirectFunctionTable(bool required) {
|
||||
}
|
||||
}
|
||||
|
||||
if (config->importTable) {
|
||||
if (ctx.arg.importTable) {
|
||||
if (existing) {
|
||||
existing->importModule = defaultModule;
|
||||
existing->importName = functionTableName;
|
||||
@@ -838,7 +838,7 @@ TableSymbol *SymbolTable::resolveIndirectFunctionTable(bool required) {
|
||||
}
|
||||
if (required)
|
||||
return createUndefinedIndirectFunctionTable(functionTableName);
|
||||
} else if ((existing && existing->isLive()) || config->exportTable ||
|
||||
} else if ((existing && existing->isLive()) || ctx.arg.exportTable ||
|
||||
required) {
|
||||
// A defined table is required. Either because the user request an exported
|
||||
// table or because the table symbol is already live. The existing table is
|
||||
@@ -885,7 +885,7 @@ void SymbolTable::addLazy(StringRef name, InputFile *file) {
|
||||
LLVM_DEBUG(dbgs() << "replacing existing undefined\n");
|
||||
const InputFile *oldFile = s->getFile();
|
||||
LazySymbol(name, 0, file).extract();
|
||||
if (!config->whyExtract.empty())
|
||||
if (!ctx.arg.whyExtract.empty())
|
||||
ctx.whyExtractRecords.emplace_back(toString(oldFile), s->getFile(), *s);
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ std::string maybeDemangleSymbol(StringRef name) {
|
||||
// `main` in the case where we need to pass it arguments.
|
||||
if (name == "__main_argc_argv")
|
||||
return "main";
|
||||
if (wasm::config->demangle)
|
||||
if (wasm::ctx.arg.demangle)
|
||||
return demangle(name);
|
||||
return name.str();
|
||||
}
|
||||
@@ -235,10 +235,10 @@ bool Symbol::isExported() const {
|
||||
// Shared libraries must export all weakly defined symbols
|
||||
// in case they contain the version that will be chosen by
|
||||
// the dynamic linker.
|
||||
if (config->shared && isLive() && isWeak() && !isHidden())
|
||||
if (ctx.arg.shared && isLive() && isWeak() && !isHidden())
|
||||
return true;
|
||||
|
||||
if (config->exportAll || (config->exportDynamic && !isHidden()))
|
||||
if (ctx.arg.exportAll || (ctx.arg.exportDynamic && !isHidden()))
|
||||
return true;
|
||||
|
||||
return isExportedExplicit();
|
||||
|
||||
@@ -139,7 +139,7 @@ public:
|
||||
|
||||
protected:
|
||||
Symbol(StringRef name, Kind k, uint32_t flags, InputFile *f)
|
||||
: name(name), file(f), symbolKind(k), referenced(!config->gcSections),
|
||||
: name(name), file(f), symbolKind(k), referenced(!ctx.arg.gcSections),
|
||||
requiresGOT(false), isUsedInRegularObj(false), forceExport(false),
|
||||
forceImport(false), canInline(false), traced(false), isStub(false),
|
||||
flags(flags) {}
|
||||
|
||||
@@ -55,7 +55,7 @@ public:
|
||||
|
||||
bool DylinkSection::isNeeded() const {
|
||||
return ctx.isPic ||
|
||||
config->unresolvedSymbols == UnresolvedPolicy::ImportDynamic ||
|
||||
ctx.arg.unresolvedSymbols == UnresolvedPolicy::ImportDynamic ||
|
||||
!ctx.sharedFiles.empty();
|
||||
}
|
||||
|
||||
@@ -162,7 +162,7 @@ void TypeSection::writeBody() {
|
||||
uint32_t ImportSection::getNumImports() const {
|
||||
assert(isSealed);
|
||||
uint32_t numImports = importedSymbols.size() + gotSymbols.size();
|
||||
if (config->memoryImport.has_value())
|
||||
if (ctx.arg.memoryImport.has_value())
|
||||
++numImports;
|
||||
return numImports;
|
||||
}
|
||||
@@ -232,20 +232,20 @@ void ImportSection::writeBody() {
|
||||
|
||||
writeUleb128(os, getNumImports(), "import count");
|
||||
|
||||
bool is64 = config->is64.value_or(false);
|
||||
bool is64 = ctx.arg.is64.value_or(false);
|
||||
|
||||
if (config->memoryImport) {
|
||||
if (ctx.arg.memoryImport) {
|
||||
WasmImport import;
|
||||
import.Module = config->memoryImport->first;
|
||||
import.Field = config->memoryImport->second;
|
||||
import.Module = ctx.arg.memoryImport->first;
|
||||
import.Field = ctx.arg.memoryImport->second;
|
||||
import.Kind = WASM_EXTERNAL_MEMORY;
|
||||
import.Memory.Flags = 0;
|
||||
import.Memory.Minimum = out.memorySec->numMemoryPages;
|
||||
if (out.memorySec->maxMemoryPages != 0 || config->sharedMemory) {
|
||||
if (out.memorySec->maxMemoryPages != 0 || ctx.arg.sharedMemory) {
|
||||
import.Memory.Flags |= WASM_LIMITS_FLAG_HAS_MAX;
|
||||
import.Memory.Maximum = out.memorySec->maxMemoryPages;
|
||||
}
|
||||
if (config->sharedMemory)
|
||||
if (ctx.arg.sharedMemory)
|
||||
import.Memory.Flags |= WASM_LIMITS_FLAG_IS_SHARED;
|
||||
if (is64)
|
||||
import.Memory.Flags |= WASM_LIMITS_FLAG_IS_64;
|
||||
@@ -351,14 +351,14 @@ void TableSection::assignIndexes() {
|
||||
void MemorySection::writeBody() {
|
||||
raw_ostream &os = bodyOutputStream;
|
||||
|
||||
bool hasMax = maxMemoryPages != 0 || config->sharedMemory;
|
||||
bool hasMax = maxMemoryPages != 0 || ctx.arg.sharedMemory;
|
||||
writeUleb128(os, 1, "memory count");
|
||||
unsigned flags = 0;
|
||||
if (hasMax)
|
||||
flags |= WASM_LIMITS_FLAG_HAS_MAX;
|
||||
if (config->sharedMemory)
|
||||
if (ctx.arg.sharedMemory)
|
||||
flags |= WASM_LIMITS_FLAG_IS_SHARED;
|
||||
if (config->is64.value_or(false))
|
||||
if (ctx.arg.is64.value_or(false))
|
||||
flags |= WASM_LIMITS_FLAG_IS_64;
|
||||
writeUleb128(os, flags, "memory limits flags");
|
||||
writeUleb128(os, numMemoryPages, "initial pages");
|
||||
@@ -415,8 +415,8 @@ void GlobalSection::addInternalGOTEntry(Symbol *sym) {
|
||||
}
|
||||
|
||||
void GlobalSection::generateRelocationCode(raw_ostream &os, bool TLS) const {
|
||||
assert(!config->extendedConst);
|
||||
bool is64 = config->is64.value_or(false);
|
||||
assert(!ctx.arg.extendedConst);
|
||||
bool is64 = ctx.arg.is64.value_or(false);
|
||||
unsigned opcode_ptr_const = is64 ? WASM_OPCODE_I64_CONST
|
||||
: WASM_OPCODE_I32_CONST;
|
||||
unsigned opcode_ptr_add = is64 ? WASM_OPCODE_I64_ADD
|
||||
@@ -466,7 +466,7 @@ void GlobalSection::writeBody() {
|
||||
writeGlobalType(os, g->getType());
|
||||
writeInitExpr(os, g->getInitExpr());
|
||||
}
|
||||
bool is64 = config->is64.value_or(false);
|
||||
bool is64 = ctx.arg.is64.value_or(false);
|
||||
uint8_t itype = is64 ? WASM_TYPE_I64 : WASM_TYPE_I32;
|
||||
for (const Symbol *sym : internalGotSymbols) {
|
||||
bool mutable_ = false;
|
||||
@@ -474,11 +474,11 @@ void GlobalSection::writeBody() {
|
||||
// In the case of dynamic linking, unless we have 'extended-const'
|
||||
// available, these global must to be mutable since they get updated to
|
||||
// the correct runtime value during `__wasm_apply_global_relocs`.
|
||||
if (!config->extendedConst && ctx.isPic && !sym->isTLS())
|
||||
if (!ctx.arg.extendedConst && ctx.isPic && !sym->isTLS())
|
||||
mutable_ = true;
|
||||
// With multi-theadeding any TLS globals must be mutable since they get
|
||||
// set during `__wasm_apply_global_tls_relocs`
|
||||
if (config->sharedMemory && sym->isTLS())
|
||||
if (ctx.arg.sharedMemory && sym->isTLS())
|
||||
mutable_ = true;
|
||||
}
|
||||
WasmGlobalType type{itype, mutable_};
|
||||
@@ -487,7 +487,7 @@ void GlobalSection::writeBody() {
|
||||
bool useExtendedConst = false;
|
||||
uint32_t globalIdx;
|
||||
int64_t offset;
|
||||
if (config->extendedConst && ctx.isPic) {
|
||||
if (ctx.arg.extendedConst && ctx.isPic) {
|
||||
if (auto *d = dyn_cast<DefinedData>(sym)) {
|
||||
if (!sym->isTLS()) {
|
||||
globalIdx = WasmSym::memoryBase->getGlobalIndex();
|
||||
@@ -518,7 +518,7 @@ void GlobalSection::writeBody() {
|
||||
// In the sharedMemory case TLS globals are set during
|
||||
// `__wasm_apply_global_tls_relocs`, but in the non-shared case
|
||||
// we know the absolute value at link time.
|
||||
initExpr = intConst(d->getVA(/*absolute=*/!config->sharedMemory), is64);
|
||||
initExpr = intConst(d->getVA(/*absolute=*/!ctx.arg.sharedMemory), is64);
|
||||
else if (auto *f = dyn_cast<FunctionSymbol>(sym))
|
||||
initExpr = intConst(f->isStub ? 0 : f->getTableIndex(), is64);
|
||||
else {
|
||||
@@ -566,7 +566,7 @@ void ElemSection::addEntry(FunctionSymbol *sym) {
|
||||
// They only exist so that the calls to missing functions can validate.
|
||||
if (sym->hasTableIndex() || sym->isStub)
|
||||
return;
|
||||
sym->setTableIndex(config->tableBase + indirectFunctions.size());
|
||||
sym->setTableIndex(ctx.arg.tableBase + indirectFunctions.size());
|
||||
indirectFunctions.emplace_back(sym);
|
||||
}
|
||||
|
||||
@@ -589,8 +589,8 @@ void ElemSection::writeBody() {
|
||||
initExpr.Inst.Opcode = WASM_OPCODE_GLOBAL_GET;
|
||||
initExpr.Inst.Value.Global = WasmSym::tableBase->getGlobalIndex();
|
||||
} else {
|
||||
bool is64 = config->is64.value_or(false);
|
||||
initExpr = intConst(config->tableBase, is64);
|
||||
bool is64 = ctx.arg.is64.value_or(false);
|
||||
initExpr = intConst(ctx.arg.tableBase, is64);
|
||||
}
|
||||
writeInitExpr(os, initExpr);
|
||||
|
||||
@@ -602,7 +602,7 @@ void ElemSection::writeBody() {
|
||||
}
|
||||
|
||||
writeUleb128(os, indirectFunctions.size(), "elem count");
|
||||
uint32_t tableIndex = config->tableBase;
|
||||
uint32_t tableIndex = ctx.arg.tableBase;
|
||||
for (const FunctionSymbol *sym : indirectFunctions) {
|
||||
assert(sym->getTableIndex() == tableIndex);
|
||||
(void) tableIndex;
|
||||
@@ -622,7 +622,7 @@ void DataCountSection::writeBody() {
|
||||
}
|
||||
|
||||
bool DataCountSection::isNeeded() const {
|
||||
return numSegments && config->sharedMemory;
|
||||
return numSegments && ctx.arg.sharedMemory;
|
||||
}
|
||||
|
||||
void LinkingSection::writeBody() {
|
||||
@@ -786,9 +786,9 @@ unsigned NameSection::numNamedDataSegments() const {
|
||||
void NameSection::writeBody() {
|
||||
{
|
||||
SubSection sub(WASM_NAMES_MODULE);
|
||||
StringRef moduleName = config->soName;
|
||||
if (config->soName.empty())
|
||||
moduleName = llvm::sys::path::filename(config->outputFile);
|
||||
StringRef moduleName = ctx.arg.soName;
|
||||
if (ctx.arg.soName.empty())
|
||||
moduleName = llvm::sys::path::filename(ctx.arg.outputFile);
|
||||
writeStr(sub.os, moduleName, "module name");
|
||||
sub.writeTo(bodyOutputStream);
|
||||
}
|
||||
@@ -917,14 +917,14 @@ void RelocSection::writeBody() {
|
||||
}
|
||||
|
||||
static size_t getHashSize() {
|
||||
switch (config->buildId) {
|
||||
switch (ctx.arg.buildId) {
|
||||
case BuildIdKind::Fast:
|
||||
case BuildIdKind::Uuid:
|
||||
return 16;
|
||||
case BuildIdKind::Sha1:
|
||||
return 20;
|
||||
case BuildIdKind::Hexstring:
|
||||
return config->buildIdVector.size();
|
||||
return ctx.arg.buildIdVector.size();
|
||||
case BuildIdKind::None:
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -228,7 +228,7 @@ class MemorySection : public SyntheticSection {
|
||||
public:
|
||||
MemorySection() : SyntheticSection(llvm::wasm::WASM_SEC_MEMORY) {}
|
||||
|
||||
bool isNeeded() const override { return !config->memoryImport.has_value(); }
|
||||
bool isNeeded() const override { return !ctx.arg.memoryImport.has_value(); }
|
||||
void writeBody() override;
|
||||
|
||||
uint64_t numMemoryPages = 0;
|
||||
@@ -286,7 +286,7 @@ public:
|
||||
// transform a `global.get` to an `i32.const`.
|
||||
void addInternalGOTEntry(Symbol *sym);
|
||||
bool needsRelocations() {
|
||||
if (config->extendedConst)
|
||||
if (ctx.arg.extendedConst)
|
||||
return false;
|
||||
return llvm::any_of(internalGotSymbols,
|
||||
[=](Symbol *sym) { return !sym->isTLS(); });
|
||||
@@ -354,7 +354,7 @@ public:
|
||||
: SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "linking"),
|
||||
initFunctions(initFunctions), dataSegments(dataSegments) {}
|
||||
bool isNeeded() const override {
|
||||
return config->relocatable || config->emitRelocs;
|
||||
return ctx.arg.relocatable || ctx.arg.emitRelocs;
|
||||
}
|
||||
void writeBody() override;
|
||||
void addToSymtab(Symbol *sym);
|
||||
@@ -373,7 +373,7 @@ public:
|
||||
: SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "name"),
|
||||
segments(segments) {}
|
||||
bool isNeeded() const override {
|
||||
if (config->stripAll && !config->keepSections.count(name))
|
||||
if (ctx.arg.stripAll && !ctx.arg.keepSections.count(name))
|
||||
return false;
|
||||
return numNames() > 0;
|
||||
}
|
||||
@@ -396,7 +396,7 @@ public:
|
||||
ProducersSection()
|
||||
: SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "producers") {}
|
||||
bool isNeeded() const override {
|
||||
if (config->stripAll && !config->keepSections.count(name))
|
||||
if (ctx.arg.stripAll && !ctx.arg.keepSections.count(name))
|
||||
return false;
|
||||
return fieldCount() > 0;
|
||||
}
|
||||
@@ -417,7 +417,7 @@ public:
|
||||
TargetFeaturesSection()
|
||||
: SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "target_features") {}
|
||||
bool isNeeded() const override {
|
||||
if (config->stripAll && !config->keepSections.count(name))
|
||||
if (ctx.arg.stripAll && !ctx.arg.keepSections.count(name))
|
||||
return false;
|
||||
return features.size() > 0;
|
||||
}
|
||||
@@ -443,7 +443,7 @@ public:
|
||||
BuildIdSection();
|
||||
void writeBody() override;
|
||||
bool isNeeded() const override {
|
||||
return config->buildId != BuildIdKind::None;
|
||||
return ctx.arg.buildId != BuildIdKind::None;
|
||||
}
|
||||
void writeBuildId(llvm::ArrayRef<uint8_t> buf);
|
||||
void writeTo(uint8_t *buf) override {
|
||||
|
||||
@@ -132,7 +132,7 @@ private:
|
||||
|
||||
void Writer::calculateCustomSections() {
|
||||
log("calculateCustomSections");
|
||||
bool stripDebug = config->stripDebug || config->stripAll;
|
||||
bool stripDebug = ctx.arg.stripDebug || ctx.arg.stripAll;
|
||||
for (ObjFile *file : ctx.objectFiles) {
|
||||
for (InputChunk *section : file->customSections) {
|
||||
// Exclude COMDAT sections that are not selected for inclusion
|
||||
@@ -172,7 +172,7 @@ void Writer::createCustomSections() {
|
||||
LLVM_DEBUG(dbgs() << "createCustomSection: " << name << "\n");
|
||||
|
||||
OutputSection *sec = make<CustomSection>(std::string(name), pair.second);
|
||||
if (config->relocatable || config->emitRelocs) {
|
||||
if (ctx.arg.relocatable || ctx.arg.emitRelocs) {
|
||||
auto *sym = make<OutputSectionSymbol>(sec);
|
||||
out.linkingSec->addToSymtab(sym);
|
||||
sec->sectionSym = sym;
|
||||
@@ -282,8 +282,8 @@ static void makeUUID(unsigned version, llvm::ArrayRef<uint8_t> fileHash,
|
||||
void Writer::writeBuildId() {
|
||||
if (!out.buildIdSec->isNeeded())
|
||||
return;
|
||||
if (config->buildId == BuildIdKind::Hexstring) {
|
||||
out.buildIdSec->writeBuildId(config->buildIdVector);
|
||||
if (ctx.arg.buildId == BuildIdKind::Hexstring) {
|
||||
out.buildIdSec->writeBuildId(ctx.arg.buildIdVector);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -292,7 +292,7 @@ void Writer::writeBuildId() {
|
||||
std::vector<uint8_t> buildId(hashSize);
|
||||
llvm::ArrayRef<uint8_t> buf{buffer->getBufferStart(), size_t(fileSize)};
|
||||
|
||||
switch (config->buildId) {
|
||||
switch (ctx.arg.buildId) {
|
||||
case BuildIdKind::Fast: {
|
||||
std::vector<uint8_t> fileHash(8);
|
||||
computeHash(fileHash, buf, [](uint8_t *dest, ArrayRef<uint8_t> arr) {
|
||||
@@ -324,9 +324,9 @@ static void setGlobalPtr(DefinedGlobal *g, uint64_t memoryPtr) {
|
||||
// to each of the input data sections as well as the explicit stack region.
|
||||
// The default memory layout is as follows, from low to high.
|
||||
//
|
||||
// - initialized data (starting at config->globalBase)
|
||||
// - initialized data (starting at ctx.arg.globalBase)
|
||||
// - BSS data (not currently implemented in llvm)
|
||||
// - explicit stack (config->ZStackSize)
|
||||
// - explicit stack (ctx.arg.ZStackSize)
|
||||
// - heap start / unallocated
|
||||
//
|
||||
// The --stack-first option means that stack is placed before any static data.
|
||||
@@ -337,33 +337,33 @@ void Writer::layoutMemory() {
|
||||
uint64_t memoryPtr = 0;
|
||||
|
||||
auto placeStack = [&]() {
|
||||
if (config->relocatable || ctx.isPic)
|
||||
if (ctx.arg.relocatable || ctx.isPic)
|
||||
return;
|
||||
memoryPtr = alignTo(memoryPtr, stackAlignment);
|
||||
if (WasmSym::stackLow)
|
||||
WasmSym::stackLow->setVA(memoryPtr);
|
||||
if (config->zStackSize != alignTo(config->zStackSize, stackAlignment))
|
||||
if (ctx.arg.zStackSize != alignTo(ctx.arg.zStackSize, stackAlignment))
|
||||
error("stack size must be " + Twine(stackAlignment) + "-byte aligned");
|
||||
log("mem: stack size = " + Twine(config->zStackSize));
|
||||
log("mem: stack size = " + Twine(ctx.arg.zStackSize));
|
||||
log("mem: stack base = " + Twine(memoryPtr));
|
||||
memoryPtr += config->zStackSize;
|
||||
memoryPtr += ctx.arg.zStackSize;
|
||||
setGlobalPtr(cast<DefinedGlobal>(WasmSym::stackPointer), memoryPtr);
|
||||
if (WasmSym::stackHigh)
|
||||
WasmSym::stackHigh->setVA(memoryPtr);
|
||||
log("mem: stack top = " + Twine(memoryPtr));
|
||||
};
|
||||
|
||||
if (config->stackFirst) {
|
||||
if (ctx.arg.stackFirst) {
|
||||
placeStack();
|
||||
if (config->globalBase) {
|
||||
if (config->globalBase < memoryPtr) {
|
||||
if (ctx.arg.globalBase) {
|
||||
if (ctx.arg.globalBase < memoryPtr) {
|
||||
error("--global-base cannot be less than stack size when --stack-first is used");
|
||||
return;
|
||||
}
|
||||
memoryPtr = config->globalBase;
|
||||
memoryPtr = ctx.arg.globalBase;
|
||||
}
|
||||
} else {
|
||||
memoryPtr = config->globalBase;
|
||||
memoryPtr = ctx.arg.globalBase;
|
||||
}
|
||||
|
||||
log("mem: global base = " + Twine(memoryPtr));
|
||||
@@ -385,7 +385,7 @@ void Writer::layoutMemory() {
|
||||
log(formatv("mem: {0,-15} offset={1,-8} size={2,-8} align={3}", seg->name,
|
||||
memoryPtr, seg->size, seg->alignment));
|
||||
|
||||
if (!config->relocatable && seg->isTLS()) {
|
||||
if (!ctx.arg.relocatable && seg->isTLS()) {
|
||||
if (WasmSym::tlsSize) {
|
||||
auto *tlsSize = cast<DefinedGlobal>(WasmSym::tlsSize);
|
||||
setGlobalPtr(tlsSize, seg->size);
|
||||
@@ -394,7 +394,7 @@ void Writer::layoutMemory() {
|
||||
auto *tlsAlign = cast<DefinedGlobal>(WasmSym::tlsAlign);
|
||||
setGlobalPtr(tlsAlign, int64_t{1} << seg->alignment);
|
||||
}
|
||||
if (!config->sharedMemory && WasmSym::tlsBase) {
|
||||
if (!ctx.arg.sharedMemory && WasmSym::tlsBase) {
|
||||
auto *tlsBase = cast<DefinedGlobal>(WasmSym::tlsBase);
|
||||
setGlobalPtr(tlsBase, memoryPtr);
|
||||
}
|
||||
@@ -404,7 +404,7 @@ void Writer::layoutMemory() {
|
||||
}
|
||||
|
||||
// Make space for the memory initialization flag
|
||||
if (config->sharedMemory && hasPassiveInitializedSegments()) {
|
||||
if (ctx.arg.sharedMemory && hasPassiveInitializedSegments()) {
|
||||
memoryPtr = alignTo(memoryPtr, 4);
|
||||
WasmSym::initMemoryFlag = symtab->addSyntheticDataSymbol(
|
||||
"__wasm_init_memory_flag", WASM_SYMBOL_VISIBILITY_HIDDEN);
|
||||
@@ -423,7 +423,7 @@ void Writer::layoutMemory() {
|
||||
if (ctx.isPic)
|
||||
out.dylinkSec->memSize = staticDataSize;
|
||||
|
||||
if (!config->stackFirst)
|
||||
if (!ctx.arg.stackFirst)
|
||||
placeStack();
|
||||
|
||||
if (WasmSym::heapBase) {
|
||||
@@ -438,31 +438,31 @@ void Writer::layoutMemory() {
|
||||
}
|
||||
|
||||
uint64_t maxMemorySetting = 1ULL << 32;
|
||||
if (config->is64.value_or(false)) {
|
||||
if (ctx.arg.is64.value_or(false)) {
|
||||
// TODO: Update once we decide on a reasonable limit here:
|
||||
// https://github.com/WebAssembly/memory64/issues/33
|
||||
maxMemorySetting = 1ULL << 34;
|
||||
}
|
||||
|
||||
if (config->initialHeap != 0) {
|
||||
if (config->initialHeap != alignTo(config->initialHeap, WasmPageSize))
|
||||
if (ctx.arg.initialHeap != 0) {
|
||||
if (ctx.arg.initialHeap != alignTo(ctx.arg.initialHeap, WasmPageSize))
|
||||
error("initial heap must be " + Twine(WasmPageSize) + "-byte aligned");
|
||||
uint64_t maxInitialHeap = maxMemorySetting - memoryPtr;
|
||||
if (config->initialHeap > maxInitialHeap)
|
||||
if (ctx.arg.initialHeap > maxInitialHeap)
|
||||
error("initial heap too large, cannot be greater than " +
|
||||
Twine(maxInitialHeap));
|
||||
memoryPtr += config->initialHeap;
|
||||
memoryPtr += ctx.arg.initialHeap;
|
||||
}
|
||||
|
||||
if (config->initialMemory != 0) {
|
||||
if (config->initialMemory != alignTo(config->initialMemory, WasmPageSize))
|
||||
if (ctx.arg.initialMemory != 0) {
|
||||
if (ctx.arg.initialMemory != alignTo(ctx.arg.initialMemory, WasmPageSize))
|
||||
error("initial memory must be " + Twine(WasmPageSize) + "-byte aligned");
|
||||
if (memoryPtr > config->initialMemory)
|
||||
if (memoryPtr > ctx.arg.initialMemory)
|
||||
error("initial memory too small, " + Twine(memoryPtr) + " bytes needed");
|
||||
if (config->initialMemory > maxMemorySetting)
|
||||
if (ctx.arg.initialMemory > maxMemorySetting)
|
||||
error("initial memory too large, cannot be greater than " +
|
||||
Twine(maxMemorySetting));
|
||||
memoryPtr = config->initialMemory;
|
||||
memoryPtr = ctx.arg.initialMemory;
|
||||
}
|
||||
|
||||
memoryPtr = alignTo(memoryPtr, WasmPageSize);
|
||||
@@ -479,23 +479,23 @@ void Writer::layoutMemory() {
|
||||
}
|
||||
|
||||
uint64_t maxMemory = 0;
|
||||
if (config->maxMemory != 0) {
|
||||
if (config->maxMemory != alignTo(config->maxMemory, WasmPageSize))
|
||||
if (ctx.arg.maxMemory != 0) {
|
||||
if (ctx.arg.maxMemory != alignTo(ctx.arg.maxMemory, WasmPageSize))
|
||||
error("maximum memory must be " + Twine(WasmPageSize) + "-byte aligned");
|
||||
if (memoryPtr > config->maxMemory)
|
||||
if (memoryPtr > ctx.arg.maxMemory)
|
||||
error("maximum memory too small, " + Twine(memoryPtr) + " bytes needed");
|
||||
if (config->maxMemory > maxMemorySetting)
|
||||
if (ctx.arg.maxMemory > maxMemorySetting)
|
||||
error("maximum memory too large, cannot be greater than " +
|
||||
Twine(maxMemorySetting));
|
||||
|
||||
maxMemory = config->maxMemory;
|
||||
} else if (config->noGrowableMemory) {
|
||||
maxMemory = ctx.arg.maxMemory;
|
||||
} else if (ctx.arg.noGrowableMemory) {
|
||||
maxMemory = memoryPtr;
|
||||
}
|
||||
|
||||
// If no maxMemory config was supplied but we are building with
|
||||
// shared memory, we need to pick a sensible upper limit.
|
||||
if (config->sharedMemory && maxMemory == 0) {
|
||||
if (ctx.arg.sharedMemory && maxMemory == 0) {
|
||||
if (ctx.isPic)
|
||||
maxMemory = maxMemorySetting;
|
||||
else
|
||||
@@ -552,7 +552,7 @@ void Writer::addSections() {
|
||||
createCustomSections();
|
||||
|
||||
addSection(out.linkingSec);
|
||||
if (config->emitRelocs || config->relocatable) {
|
||||
if (ctx.arg.emitRelocs || ctx.arg.relocatable) {
|
||||
createRelocSections();
|
||||
}
|
||||
|
||||
@@ -583,18 +583,18 @@ void Writer::populateTargetFeatures() {
|
||||
allowed.insert("mutable-globals");
|
||||
}
|
||||
|
||||
if (config->extraFeatures.has_value()) {
|
||||
auto &extraFeatures = *config->extraFeatures;
|
||||
if (ctx.arg.extraFeatures.has_value()) {
|
||||
auto &extraFeatures = *ctx.arg.extraFeatures;
|
||||
allowed.insert(extraFeatures.begin(), extraFeatures.end());
|
||||
}
|
||||
|
||||
// Only infer used features if user did not specify features
|
||||
bool inferFeatures = !config->features.has_value();
|
||||
bool inferFeatures = !ctx.arg.features.has_value();
|
||||
|
||||
if (!inferFeatures) {
|
||||
auto &explicitFeatures = *config->features;
|
||||
auto &explicitFeatures = *ctx.arg.features;
|
||||
allowed.insert(explicitFeatures.begin(), explicitFeatures.end());
|
||||
if (!config->checkFeatures)
|
||||
if (!ctx.arg.checkFeatures)
|
||||
goto done;
|
||||
}
|
||||
|
||||
@@ -626,10 +626,10 @@ void Writer::populateTargetFeatures() {
|
||||
for (const auto &key : used.keys())
|
||||
allowed.insert(std::string(key));
|
||||
|
||||
if (!config->checkFeatures)
|
||||
if (!ctx.arg.checkFeatures)
|
||||
goto done;
|
||||
|
||||
if (config->sharedMemory) {
|
||||
if (ctx.arg.sharedMemory) {
|
||||
if (disallowed.count("shared-mem"))
|
||||
error("--shared-memory is disallowed by " + disallowed["shared-mem"] +
|
||||
" because it was not compiled with 'atomics' or 'bulk-memory' "
|
||||
@@ -679,19 +679,19 @@ done:
|
||||
// instruction, then we can also avoid including the segments.
|
||||
// Finally, if we are emitting relocations, they may refer to locations within
|
||||
// the bss segments, so these segments need to exist in the binary.
|
||||
if (config->emitRelocs ||
|
||||
(config->memoryImport.has_value() && !allowed.count("bulk-memory")))
|
||||
if (ctx.arg.emitRelocs ||
|
||||
(ctx.arg.memoryImport.has_value() && !allowed.count("bulk-memory")))
|
||||
ctx.emitBssSegments = true;
|
||||
|
||||
if (allowed.count("extended-const"))
|
||||
config->extendedConst = true;
|
||||
ctx.arg.extendedConst = true;
|
||||
|
||||
for (auto &feature : allowed)
|
||||
log("Allowed feature: " + feature);
|
||||
}
|
||||
|
||||
void Writer::checkImportExportTargetFeatures() {
|
||||
if (config->relocatable || !config->checkFeatures)
|
||||
if (ctx.arg.relocatable || !ctx.arg.checkFeatures)
|
||||
return;
|
||||
|
||||
if (out.targetFeaturesSec->features.count("mutable-globals") == 0) {
|
||||
@@ -727,14 +727,14 @@ static bool shouldImport(Symbol *sym) {
|
||||
// When a symbol is weakly defined in a shared library we need to allow
|
||||
// it to be overridden by another module so need to both import
|
||||
// and export the symbol.
|
||||
if (config->shared && sym->isWeak() && !sym->isUndefined() &&
|
||||
if (ctx.arg.shared && sym->isWeak() && !sym->isUndefined() &&
|
||||
!sym->isHidden())
|
||||
return true;
|
||||
if (sym->isShared())
|
||||
return true;
|
||||
if (!sym->isUndefined())
|
||||
return false;
|
||||
if (sym->isWeak() && !config->relocatable && !ctx.isPic)
|
||||
if (sym->isWeak() && !ctx.arg.relocatable && !ctx.isPic)
|
||||
return false;
|
||||
|
||||
// In PIC mode we only need to import functions when they are called directly.
|
||||
@@ -745,10 +745,10 @@ static bool shouldImport(Symbol *sym) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ctx.isPic || config->relocatable || config->importUndefined ||
|
||||
config->unresolvedSymbols == UnresolvedPolicy::ImportDynamic)
|
||||
if (ctx.isPic || ctx.arg.relocatable || ctx.arg.importUndefined ||
|
||||
ctx.arg.unresolvedSymbols == UnresolvedPolicy::ImportDynamic)
|
||||
return true;
|
||||
if (config->allowUndefinedSymbols.count(sym->getName()) != 0)
|
||||
if (ctx.arg.allowUndefinedSymbols.count(sym->getName()) != 0)
|
||||
return true;
|
||||
|
||||
return sym->isImported();
|
||||
@@ -773,12 +773,12 @@ void Writer::calculateImports() {
|
||||
}
|
||||
|
||||
void Writer::calculateExports() {
|
||||
if (config->relocatable)
|
||||
if (ctx.arg.relocatable)
|
||||
return;
|
||||
|
||||
if (!config->relocatable && config->memoryExport.has_value()) {
|
||||
if (!ctx.arg.relocatable && ctx.arg.memoryExport.has_value()) {
|
||||
out.exportSec->exports.push_back(
|
||||
WasmExport{*config->memoryExport, WASM_EXTERNAL_MEMORY, 0});
|
||||
WasmExport{*ctx.arg.memoryExport, WASM_EXTERNAL_MEMORY, 0});
|
||||
}
|
||||
|
||||
unsigned globalIndex =
|
||||
@@ -827,7 +827,7 @@ void Writer::calculateExports() {
|
||||
}
|
||||
|
||||
void Writer::populateSymtab() {
|
||||
if (!config->relocatable && !config->emitRelocs)
|
||||
if (!ctx.arg.relocatable && !ctx.arg.emitRelocs)
|
||||
return;
|
||||
|
||||
for (Symbol *sym : symtab->symbols())
|
||||
@@ -931,13 +931,13 @@ static void finalizeIndirectFunctionTable() {
|
||||
out.importSec->addImport(WasmSym::indirectFunctionTable);
|
||||
}
|
||||
|
||||
uint32_t tableSize = config->tableBase + out.elemSec->numEntries();
|
||||
uint32_t tableSize = ctx.arg.tableBase + out.elemSec->numEntries();
|
||||
WasmLimits limits = {0, tableSize, 0};
|
||||
if (WasmSym::indirectFunctionTable->isDefined() && !config->growableTable) {
|
||||
if (WasmSym::indirectFunctionTable->isDefined() && !ctx.arg.growableTable) {
|
||||
limits.Flags |= WASM_LIMITS_FLAG_HAS_MAX;
|
||||
limits.Maximum = limits.Minimum;
|
||||
}
|
||||
if (config->is64.value_or(false))
|
||||
if (ctx.arg.is64.value_or(false))
|
||||
limits.Flags |= WASM_LIMITS_FLAG_IS_64;
|
||||
WasmSym::indirectFunctionTable->setLimits(limits);
|
||||
}
|
||||
@@ -1001,7 +1001,7 @@ static StringRef getOutputDataSegmentName(const InputChunk &seg) {
|
||||
// symbols are be relative to single __tls_base.
|
||||
if (seg.isTLS())
|
||||
return ".tdata";
|
||||
if (!config->mergeDataSegments)
|
||||
if (!ctx.arg.mergeDataSegments)
|
||||
return seg.name;
|
||||
if (seg.name.starts_with(".text."))
|
||||
return ".text";
|
||||
@@ -1017,9 +1017,9 @@ static StringRef getOutputDataSegmentName(const InputChunk &seg) {
|
||||
OutputSegment *Writer::createOutputSegment(StringRef name) {
|
||||
LLVM_DEBUG(dbgs() << "new segment: " << name << "\n");
|
||||
OutputSegment *s = make<OutputSegment>(name);
|
||||
if (config->sharedMemory)
|
||||
if (ctx.arg.sharedMemory)
|
||||
s->initFlags = WASM_DATA_SEGMENT_IS_PASSIVE;
|
||||
if (!config->relocatable && name.starts_with(".bss"))
|
||||
if (!ctx.arg.relocatable && name.starts_with(".bss"))
|
||||
s->isBss = true;
|
||||
segments.push_back(s);
|
||||
return s;
|
||||
@@ -1035,7 +1035,7 @@ void Writer::createOutputSegments() {
|
||||
// When running in relocatable mode we can't merge segments that are part
|
||||
// of comdat groups since the ultimate linker needs to be able exclude or
|
||||
// include them individually.
|
||||
if (config->relocatable && !segment->getComdatName().empty()) {
|
||||
if (ctx.arg.relocatable && !segment->getComdatName().empty()) {
|
||||
s = createOutputSegment(name);
|
||||
} else {
|
||||
if (segmentMap.count(name) == 0)
|
||||
@@ -1075,8 +1075,8 @@ void Writer::combineOutputSegments() {
|
||||
// combines all data segments into a single .data segment.
|
||||
// This restriction does not apply when the extended const extension is
|
||||
// available: https://github.com/WebAssembly/extended-const
|
||||
assert(!config->extendedConst);
|
||||
assert(ctx.isPic && !config->sharedMemory);
|
||||
assert(!ctx.arg.extendedConst);
|
||||
assert(ctx.isPic && !ctx.arg.sharedMemory);
|
||||
if (segments.size() <= 1)
|
||||
return;
|
||||
OutputSegment *combined = make<OutputSegment>(".data");
|
||||
@@ -1117,7 +1117,7 @@ static void createFunction(DefinedFunction *func, StringRef bodyContent) {
|
||||
bool Writer::needsPassiveInitialization(const OutputSegment *segment) {
|
||||
// If bulk memory features is supported then we can perform bss initialization
|
||||
// (via memory.fill) during `__wasm_init_memory`.
|
||||
if (config->memoryImport.has_value() && !segment->requiredInBinary())
|
||||
if (ctx.arg.memoryImport.has_value() && !segment->requiredInBinary())
|
||||
return true;
|
||||
return segment->initFlags & WASM_DATA_SEGMENT_IS_PASSIVE;
|
||||
}
|
||||
@@ -1129,7 +1129,7 @@ bool Writer::hasPassiveInitializedSegments() {
|
||||
}
|
||||
|
||||
void Writer::createSyntheticInitFunctions() {
|
||||
if (config->relocatable)
|
||||
if (ctx.arg.relocatable)
|
||||
return;
|
||||
|
||||
static WasmSignature nullSignature = {{}, {}};
|
||||
@@ -1146,14 +1146,14 @@ void Writer::createSyntheticInitFunctions() {
|
||||
"__wasm_init_memory", WASM_SYMBOL_VISIBILITY_HIDDEN,
|
||||
make<SyntheticFunction>(nullSignature, "__wasm_init_memory"));
|
||||
WasmSym::initMemory->markLive();
|
||||
if (config->sharedMemory) {
|
||||
if (ctx.arg.sharedMemory) {
|
||||
// This global is assigned during __wasm_init_memory in the shared memory
|
||||
// case.
|
||||
WasmSym::tlsBase->markLive();
|
||||
}
|
||||
}
|
||||
|
||||
if (config->sharedMemory) {
|
||||
if (ctx.arg.sharedMemory) {
|
||||
if (out.globalSec->needsTLSRelocations()) {
|
||||
WasmSym::applyGlobalTLSRelocs = symtab->addSyntheticFunction(
|
||||
"__wasm_apply_global_tls_relocs", WASM_SYMBOL_VISIBILITY_HIDDEN,
|
||||
@@ -1203,11 +1203,11 @@ void Writer::createInitMemoryFunction() {
|
||||
assert(WasmSym::initMemory);
|
||||
assert(hasPassiveInitializedSegments());
|
||||
uint64_t flagAddress;
|
||||
if (config->sharedMemory) {
|
||||
if (ctx.arg.sharedMemory) {
|
||||
assert(WasmSym::initMemoryFlag);
|
||||
flagAddress = WasmSym::initMemoryFlag->getVA();
|
||||
}
|
||||
bool is64 = config->is64.value_or(false);
|
||||
bool is64 = ctx.arg.is64.value_or(false);
|
||||
std::string bodyContent;
|
||||
{
|
||||
raw_string_ostream os(bodyContent);
|
||||
@@ -1271,7 +1271,7 @@ void Writer::createInitMemoryFunction() {
|
||||
}
|
||||
};
|
||||
|
||||
if (config->sharedMemory) {
|
||||
if (ctx.arg.sharedMemory) {
|
||||
// With PIC code we cache the flag address in local 0
|
||||
if (ctx.isPic) {
|
||||
writeUleb128(os, 1, "num local decls");
|
||||
@@ -1334,7 +1334,7 @@ void Writer::createInitMemoryFunction() {
|
||||
// When we initialize the TLS segment we also set the `__tls_base`
|
||||
// global. This allows the runtime to use this static copy of the
|
||||
// TLS data for the first/main thread.
|
||||
if (config->sharedMemory && s->isTLS()) {
|
||||
if (ctx.arg.sharedMemory && s->isTLS()) {
|
||||
if (ctx.isPic) {
|
||||
// Cache the result of the addionion in local 0
|
||||
writeU8(os, WASM_OPCODE_LOCAL_TEE, "local.tee");
|
||||
@@ -1368,7 +1368,7 @@ void Writer::createInitMemoryFunction() {
|
||||
}
|
||||
}
|
||||
|
||||
if (config->sharedMemory) {
|
||||
if (ctx.arg.sharedMemory) {
|
||||
// Set flag to 2 to mark end of initialization
|
||||
writeGetFlagAddress();
|
||||
writeI32Const(os, 2, "flag value");
|
||||
@@ -1407,7 +1407,7 @@ void Writer::createInitMemoryFunction() {
|
||||
if (needsPassiveInitialization(s) && !s->isBss) {
|
||||
// The TLS region should not be dropped since its is needed
|
||||
// during the initialization of each thread (__wasm_init_tls).
|
||||
if (config->sharedMemory && s->isTLS())
|
||||
if (ctx.arg.sharedMemory && s->isTLS())
|
||||
continue;
|
||||
// data.drop instruction
|
||||
writeU8(os, WASM_OPCODE_MISC_PREFIX, "bulk-memory prefix");
|
||||
@@ -1460,7 +1460,7 @@ void Writer::createApplyDataRelocationsFunction() {
|
||||
writeUleb128(os, 0, "num locals");
|
||||
bool generated = false;
|
||||
for (const OutputSegment *seg : segments)
|
||||
if (!config->sharedMemory || !seg->isTLS())
|
||||
if (!ctx.arg.sharedMemory || !seg->isTLS())
|
||||
for (const InputChunk *inSeg : seg->inputSegments)
|
||||
generated |= inSeg->generateRelocationCode(os);
|
||||
|
||||
@@ -1656,7 +1656,7 @@ void Writer::createInitTLSFunction() {
|
||||
// This is then used either when creating the output linking section or to
|
||||
// synthesize the "__wasm_call_ctors" function.
|
||||
void Writer::calculateInitFunctions() {
|
||||
if (!config->relocatable && !WasmSym::callCtors->isLive())
|
||||
if (!ctx.arg.relocatable && !WasmSym::callCtors->isLive())
|
||||
return;
|
||||
|
||||
for (ObjFile *file : ctx.objectFiles) {
|
||||
@@ -1708,7 +1708,7 @@ void Writer::run() {
|
||||
// For PIC code the table base is assigned dynamically by the loader.
|
||||
// For non-PIC, we start at 1 so that accessing table index 0 always traps.
|
||||
if (!ctx.isPic && WasmSym::definedTableBase)
|
||||
WasmSym::definedTableBase->setVA(config->tableBase);
|
||||
WasmSym::definedTableBase->setVA(ctx.arg.tableBase);
|
||||
|
||||
log("-- createOutputSegments");
|
||||
createOutputSegments();
|
||||
@@ -1717,7 +1717,7 @@ void Writer::run() {
|
||||
log("-- layoutMemory");
|
||||
layoutMemory();
|
||||
|
||||
if (!config->relocatable) {
|
||||
if (!ctx.arg.relocatable) {
|
||||
// Create linker synthesized __start_SECNAME/__stop_SECNAME symbols
|
||||
// This has to be done after memory layout is performed.
|
||||
for (const OutputSegment *seg : segments) {
|
||||
@@ -1725,7 +1725,7 @@ void Writer::run() {
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &pair : config->exportedSymbols) {
|
||||
for (auto &pair : ctx.arg.exportedSymbols) {
|
||||
Symbol *sym = symtab->find(pair.first());
|
||||
if (sym && sym->isDefined())
|
||||
sym->forceExport = true;
|
||||
@@ -1733,12 +1733,12 @@ void Writer::run() {
|
||||
|
||||
// Delay reporting errors about explicit exports until after
|
||||
// addStartStopSymbols which can create optional symbols.
|
||||
for (auto &name : config->requiredExports) {
|
||||
for (auto &name : ctx.arg.requiredExports) {
|
||||
Symbol *sym = symtab->find(name);
|
||||
if (!sym || !sym->isDefined()) {
|
||||
if (config->unresolvedSymbols == UnresolvedPolicy::ReportError)
|
||||
if (ctx.arg.unresolvedSymbols == UnresolvedPolicy::ReportError)
|
||||
error(Twine("symbol exported via --export not found: ") + name);
|
||||
if (config->unresolvedSymbols == UnresolvedPolicy::Warn)
|
||||
if (ctx.arg.unresolvedSymbols == UnresolvedPolicy::Warn)
|
||||
warn(Twine("symbol exported via --export not found: ") + name);
|
||||
}
|
||||
}
|
||||
@@ -1750,7 +1750,7 @@ void Writer::run() {
|
||||
// `__memory_base` import. Unless we support the extended const expression we
|
||||
// can't do addition inside the constant expression, so we much combine the
|
||||
// segments into a single one that can live at `__memory_base`.
|
||||
if (ctx.isPic && !config->extendedConst && !config->sharedMemory) {
|
||||
if (ctx.isPic && !ctx.arg.extendedConst && !ctx.arg.sharedMemory) {
|
||||
// In shared memory mode all data segments are passive and initialized
|
||||
// via __wasm_init_memory.
|
||||
log("-- combineOutputSegments");
|
||||
@@ -1774,7 +1774,7 @@ void Writer::run() {
|
||||
log("-- calculateInitFunctions");
|
||||
calculateInitFunctions();
|
||||
|
||||
if (!config->relocatable) {
|
||||
if (!ctx.arg.relocatable) {
|
||||
// Create linker synthesized functions
|
||||
if (WasmSym::applyGlobalRelocs)
|
||||
createApplyGlobalRelocationsFunction();
|
||||
@@ -1793,7 +1793,7 @@ void Writer::run() {
|
||||
// If the input contains a call to `__wasm_call_ctors`, either in one of
|
||||
// the input objects or an explicit export from the command-line, we
|
||||
// assume ctors and dtors are taken care of already.
|
||||
if (!config->relocatable && !ctx.isPic &&
|
||||
if (!ctx.arg.relocatable && !ctx.isPic &&
|
||||
!WasmSym::callCtors->isUsedInRegularObj &&
|
||||
!WasmSym::callCtors->isExported()) {
|
||||
log("-- createCommandExportWrappers");
|
||||
@@ -1861,14 +1861,14 @@ void Writer::run() {
|
||||
|
||||
// Open a result file.
|
||||
void Writer::openFile() {
|
||||
log("writing: " + config->outputFile);
|
||||
log("writing: " + ctx.arg.outputFile);
|
||||
|
||||
Expected<std::unique_ptr<FileOutputBuffer>> bufferOrErr =
|
||||
FileOutputBuffer::create(config->outputFile, fileSize,
|
||||
FileOutputBuffer::create(ctx.arg.outputFile, fileSize,
|
||||
FileOutputBuffer::F_executable);
|
||||
|
||||
if (!bufferOrErr)
|
||||
error("failed to open " + config->outputFile + ": " +
|
||||
error("failed to open " + ctx.arg.outputFile + ": " +
|
||||
toString(bufferOrErr.takeError()));
|
||||
else
|
||||
buffer = std::move(*bufferOrErr);
|
||||
|
||||
Reference in New Issue
Block a user