aboutsummaryrefslogtreecommitdiff
path: root/src/link
diff options
context:
space:
mode:
Diffstat (limited to 'src/link')
-rw-r--r--src/link/Coff.zig21
-rw-r--r--src/link/Coff/lld.zig15
-rw-r--r--src/link/Elf.zig29
-rw-r--r--src/link/MachO.zig17
-rw-r--r--src/link/MachO/zld.zig5
-rw-r--r--src/link/Wasm.zig51
6 files changed, 100 insertions, 38 deletions
diff --git a/src/link/Coff.zig b/src/link/Coff.zig
index 861ec030b3..53f999b965 100644
--- a/src/link/Coff.zig
+++ b/src/link/Coff.zig
@@ -17,6 +17,7 @@ dynamicbase: bool,
major_subsystem_version: u16,
minor_subsystem_version: u16,
lib_dirs: []const []const u8,
+entry: link.File.OpenOptions.Entry,
entry_addr: ?u32,
module_definition_file: ?[]const u8,
pdb_out_path: ?[]const u8,
@@ -303,7 +304,12 @@ pub fn createEmpty(
.Obj => 0,
},
+ // Subsystem depends on the set of public symbol names from linked objects.
+ // See LinkerDriver::inferSubsystem from the LLD project for the flow chart.
.subsystem = options.subsystem,
+
+ .entry = options.entry,
+
.tsaware = options.tsaware,
.nxcompat = options.nxcompat,
.dynamicbase = options.dynamicbase,
@@ -2498,7 +2504,20 @@ inline fn getSizeOfImage(self: Coff) u32 {
/// Returns symbol location corresponding to the set entrypoint (if any).
pub fn getEntryPoint(self: Coff) ?SymbolWithLoc {
const comp = self.base.comp;
- const entry_name = comp.config.entry orelse return null;
+
+ // TODO This is incomplete.
+ // The entry symbol name depends on the subsystem as well as the set of
+ // public symbol names from linked objects.
+ // See LinkerDriver::findDefaultEntry from the LLD project for the flow chart.
+ const entry_name = switch (self.entry) {
+ .disabled => return null,
+ .default => switch (comp.config.output_mode) {
+ .Exe => "wWinMainCRTStartup",
+ .Obj, .Lib => return null,
+ },
+ .enabled => "wWinMainCRTStartup",
+ .named => |name| name,
+ };
const global_index = self.resolver.get(entry_name) orelse return null;
return self.globals.items[global_index];
}
diff --git a/src/link/Coff/lld.zig b/src/link/Coff/lld.zig
index 5b01f63645..6afe741f66 100644
--- a/src/link/Coff/lld.zig
+++ b/src/link/Coff/lld.zig
@@ -52,6 +52,13 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
const link_in_crt = comp.config.link_libc and is_exe_or_dyn_lib;
const target = comp.root_mod.resolved_target.result;
const optimize_mode = comp.root_mod.optimize_mode;
+ const entry_name: ?[]const u8 = switch (self.entry) {
+ // This logic isn't quite right for disabled or enabled. No point in fixing it
+ // when the goal is to eliminate dependency on LLD anyway.
+ // https://github.com/ziglang/zig/issues/17751
+ .disabled, .default, .enabled => null,
+ .named => |name| name,
+ };
// See link/Elf.zig for comments on how this mechanism works.
const id_symlink_basename = "lld.id";
@@ -80,7 +87,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
}
}
try man.addOptionalFile(module_obj_path);
- man.hash.addOptionalBytes(comp.config.entry);
+ man.hash.addOptionalBytes(entry_name);
man.hash.add(self.base.stack_size);
man.hash.add(self.image_base);
man.hash.addListOfBytes(self.lib_dirs);
@@ -218,8 +225,8 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
try argv.append("-DLL");
}
- if (comp.config.entry) |entry| {
- try argv.append(try allocPrint(arena, "-ENTRY:{s}", .{entry}));
+ if (entry_name) |name| {
+ try argv.append(try allocPrint(arena, "-ENTRY:{s}", .{name}));
}
if (self.tsaware) {
@@ -441,7 +448,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
}
} else {
try argv.append("-NODEFAULTLIB");
- if (!is_lib and comp.config.entry == null) {
+ if (!is_lib and entry_name == null) {
if (comp.module) |module| {
if (module.stage1_flags.have_winmain_crt_startup) {
try argv.append("-ENTRY:WinMainCRTStartup");
diff --git a/src/link/Elf.zig b/src/link/Elf.zig
index ea8454490c..65fc0ff5a3 100644
--- a/src/link/Elf.zig
+++ b/src/link/Elf.zig
@@ -25,6 +25,7 @@ linker_script: ?[]const u8,
version_script: ?[]const u8,
print_icf_sections: bool,
print_map: bool,
+entry_name: ?[]const u8,
ptr_width: PtrWidth,
@@ -290,6 +291,13 @@ pub fn createEmpty(
.page_size = page_size,
.default_sym_version = default_sym_version,
+ .entry_name = switch (options.entry) {
+ .disabled => null,
+ .default => if (output_mode != .Exe) null else defaultEntrySymbolName(target.cpu.arch),
+ .enabled => defaultEntrySymbolName(target.cpu.arch),
+ .named => |name| name,
+ },
+
.image_base = b: {
if (is_dyn_lib) break :b 0;
if (output_mode == .Exe and comp.config.pie) break :b 0;
@@ -1305,7 +1313,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
// Look for entry address in objects if not set by the incremental compiler.
if (self.entry_index == null) {
- if (comp.config.entry) |name| {
+ if (self.entry_name) |name| {
self.entry_index = self.globalByName(name);
}
}
@@ -1679,9 +1687,8 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
}
}
- if (comp.config.entry) |entry| {
- try argv.append("--entry");
- try argv.append(entry);
+ if (self.entry_name) |name| {
+ try argv.appendSlice(&.{ "--entry", name });
}
for (self.base.rpath_list) |rpath| {
@@ -2427,7 +2434,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
// We can skip hashing libc and libc++ components that we are in charge of building from Zig
// installation sources because they are always a product of the compiler version + target information.
- man.hash.addOptionalBytes(comp.config.entry);
+ man.hash.addOptionalBytes(self.entry_name);
man.hash.add(self.image_base);
man.hash.add(self.base.gc_sections);
man.hash.addOptional(self.sort_section);
@@ -2563,9 +2570,8 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
.ReleaseFast, .ReleaseSafe => try argv.append("-O3"),
}
- if (comp.config.entry) |entry| {
- try argv.append("--entry");
- try argv.append(entry);
+ if (self.entry_name) |name| {
+ try argv.appendSlice(&.{ "--entry", name });
}
for (self.base.force_undefined_symbols.keys()) |sym| {
@@ -6512,6 +6518,13 @@ const RelaSectionTable = std.AutoArrayHashMapUnmanaged(u32, RelaSection);
pub const R_X86_64_ZIG_GOT32 = elf.R_X86_64_NUM + 1;
pub const R_X86_64_ZIG_GOTPCREL = elf.R_X86_64_NUM + 2;
+fn defaultEntrySymbolName(cpu_arch: std.Target.Cpu.Arch) []const u8 {
+ return switch (cpu_arch) {
+ .mips, .mipsel, .mips64, .mips64el => "__start",
+ else => "_start",
+ };
+}
+
const std = @import("std");
const build_options = @import("build_options");
const builtin = @import("builtin");
diff --git a/src/link/MachO.zig b/src/link/MachO.zig
index d8fc71c0f0..8c0874e3cb 100644
--- a/src/link/MachO.zig
+++ b/src/link/MachO.zig
@@ -1,4 +1,5 @@
base: File,
+entry_name: ?[]const u8,
/// If this is not null, an object file is created by LLVM and emitted to zcu_object_sub_path.
llvm_object: ?*LlvmObject = null,
@@ -231,6 +232,12 @@ pub fn createEmpty(
.install_name = options.install_name,
.entitlements = options.entitlements,
.compatibility_version = options.compatibility_version,
+ .entry_name = switch (options.entry) {
+ .disabled => null,
+ .default => if (output_mode != .Exe) null else default_entry_symbol_name,
+ .enabled => default_entry_symbol_name,
+ .named => |name| name,
+ },
};
if (use_llvm and comp.config.have_zcu) {
self.llvm_object = try LlvmObject.create(arena, comp);
@@ -1629,8 +1636,9 @@ pub fn resolveSymbols(self: *MachO) !void {
// we search for it in libraries should there be no object files specified
// on the linker line.
if (output_mode == .Exe) {
- const entry_name = comp.config.entry.?;
- _ = try self.addUndefined(entry_name, .{});
+ if (self.entry_name) |entry_name| {
+ _ = try self.addUndefined(entry_name, .{});
+ }
}
// Force resolution of any symbols requested by the user.
@@ -5085,8 +5093,7 @@ pub fn getStubsEntryAddress(self: *MachO, sym_with_loc: SymbolWithLoc) ?u64 {
/// Returns symbol location corresponding to the set entrypoint if any.
/// Asserts output mode is executable.
pub fn getEntryPoint(self: MachO) ?SymbolWithLoc {
- const comp = self.base.comp;
- const entry_name = comp.config.entry orelse return null;
+ const entry_name = self.entry_name orelse return null;
const global = self.getGlobal(entry_name) orelse return null;
return global;
}
@@ -5645,6 +5652,8 @@ pub fn logAtom(self: *MachO, atom_index: Atom.Index, logger: anytype) void {
}
}
+const default_entry_symbol_name = "_main";
+
pub const base_tag: File.Tag = File.Tag.macho;
pub const N_DEAD: u16 = @as(u16, @bitCast(@as(i16, -1)));
pub const N_BOUNDARY: u16 = @as(u16, @bitCast(@as(i16, -2)));
diff --git a/src/link/MachO/zld.zig b/src/link/MachO/zld.zig
index fa6aa152e4..05fa8e671a 100644
--- a/src/link/MachO/zld.zig
+++ b/src/link/MachO/zld.zig
@@ -276,9 +276,8 @@ pub fn linkWithZld(
try argv.append("-dead_strip_dylibs");
}
- if (comp.config.entry) |entry| {
- try argv.append("-e");
- try argv.append(entry);
+ if (macho_file.entry_name) |entry_name| {
+ try argv.appendSlice(&.{ "-e", entry_name });
}
for (objects) |obj| {
diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig
index b4b0f16d4a..91653ce641 100644
--- a/src/link/Wasm.zig
+++ b/src/link/Wasm.zig
@@ -37,6 +37,7 @@ pub const Relocation = types.Relocation;
pub const base_tag: link.File.Tag = .wasm;
base: link.File,
+entry_name: ?[]const u8,
import_symbols: bool,
export_symbol_names: []const []const u8,
global_base: ?u64,
@@ -397,6 +398,7 @@ pub fn createEmpty(
const use_llvm = comp.config.use_llvm;
const output_mode = comp.config.output_mode;
const shared_memory = comp.config.shared_memory;
+ const wasi_exec_model = comp.config.wasi_exec_model;
// If using LLD to link, this code should produce an object file so that it
// can be passed to LLD.
@@ -434,6 +436,13 @@ pub fn createEmpty(
.initial_memory = options.initial_memory,
.max_memory = options.max_memory,
.wasi_emulated_libs = options.wasi_emulated_libs,
+
+ .entry_name = switch (options.entry) {
+ .disabled => null,
+ .default => if (output_mode != .Exe) null else defaultEntrySymbolName(wasi_exec_model),
+ .enabled => defaultEntrySymbolName(wasi_exec_model),
+ .named => |name| name,
+ },
};
if (use_llvm and comp.config.have_zcu) {
wasm.llvm_object = try LlvmObject.create(arena, comp);
@@ -3042,7 +3051,7 @@ fn setupExports(wasm: *Wasm) !void {
fn setupStart(wasm: *Wasm) !void {
const comp = wasm.base.comp;
// do not export entry point if user set none or no default was set.
- const entry_name = comp.config.entry orelse return;
+ const entry_name = wasm.entry_name orelse return;
const symbol_loc = wasm.findGlobalSymbol(entry_name) orelse {
log.err("Entry symbol '{s}' missing, use '-fno-entry' to suppress", .{entry_name});
@@ -3475,8 +3484,8 @@ fn resetState(wasm: *Wasm) void {
}
pub fn flush(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
- const use_lld = build_options.have_llvm and wasm.base.comp.config.use_lld;
- const use_llvm = wasm.base.comp.config.use_llvm;
+ const use_lld = build_options.have_llvm and comp.config.use_lld;
+ const use_llvm = comp.config.use_llvm;
if (use_lld) {
return wasm.linkWithLLD(comp, prog_node);
@@ -3492,7 +3501,7 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l
const tracy = trace(@src());
defer tracy.end();
- const gpa = wasm.base.comp.gpa;
+ const gpa = comp.gpa;
const shared_memory = comp.config.shared_memory;
const import_memory = comp.config.import_memory;
@@ -3503,8 +3512,8 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l
const directory = wasm.base.emit.directory; // Just an alias to make it shorter to type.
const full_out_path = try directory.join(arena, &[_][]const u8{wasm.base.emit.sub_path});
- const opt_zcu = wasm.base.comp.module;
- const use_llvm = wasm.base.comp.config.use_llvm;
+ const opt_zcu = comp.module;
+ const use_llvm = comp.config.use_llvm;
// If there is no Zig code to compile, then we should skip flushing the output file because it
// will not be part of the linker line anyway.
@@ -3535,7 +3544,7 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l
defer if (!wasm.base.disable_lld_caching) man.deinit();
var digest: [Cache.hex_digest_len]u8 = undefined;
- const objects = wasm.base.comp.objects;
+ const objects = comp.objects;
// NOTE: The following section must be maintained to be equal
// as the section defined in `linkWithLLD`
@@ -3556,7 +3565,7 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l
}
try man.addOptionalFile(module_obj_path);
try man.addOptionalFile(compiler_rt_path);
- man.hash.addOptionalBytes(wasm.base.comp.config.entry);
+ man.hash.addOptionalBytes(wasm.entry_name);
man.hash.add(wasm.base.stack_size);
man.hash.add(wasm.base.build_id);
man.hash.add(import_memory);
@@ -3605,12 +3614,12 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l
var positionals = std.ArrayList([]const u8).init(arena);
try positionals.ensureUnusedCapacity(objects.len);
- const target = wasm.base.comp.root_mod.resolved_target.result;
- const output_mode = wasm.base.comp.config.output_mode;
- const link_mode = wasm.base.comp.config.link_mode;
- const link_libc = wasm.base.comp.config.link_libc;
- const link_libcpp = wasm.base.comp.config.link_libcpp;
- const wasi_exec_model = wasm.base.comp.config.wasi_exec_model;
+ const target = comp.root_mod.resolved_target.result;
+ const output_mode = comp.config.output_mode;
+ const link_mode = comp.config.link_mode;
+ const link_libc = comp.config.link_libc;
+ const link_libcpp = comp.config.link_libcpp;
+ const wasi_exec_model = comp.config.wasi_exec_model;
// When the target os is WASI, we allow linking with WASI-LIBC
if (target.os.tag == .wasi) {
@@ -4648,7 +4657,7 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
}
try man.addOptionalFile(module_obj_path);
try man.addOptionalFile(compiler_rt_path);
- man.hash.addOptionalBytes(wasm.base.comp.config.entry);
+ man.hash.addOptionalBytes(wasm.entry_name);
man.hash.add(wasm.base.stack_size);
man.hash.add(wasm.base.build_id);
man.hash.add(import_memory);
@@ -4799,9 +4808,8 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
try argv.append("--export-dynamic");
}
- if (comp.config.entry) |entry| {
- try argv.append("--entry");
- try argv.append(entry);
+ if (wasm.entry_name) |entry_name| {
+ try argv.appendSlice(&.{ "--entry", entry_name });
} else {
try argv.append("--no-entry");
}
@@ -5347,3 +5355,10 @@ fn mark(wasm: *Wasm, loc: SymbolLoc) !void {
try wasm.mark(target_loc.finalLoc(wasm));
}
}
+
+fn defaultEntrySymbolName(wasi_exec_model: std.builtin.WasiExecModel) []const u8 {
+ return switch (wasi_exec_model) {
+ .reactor => "_initialize",
+ .command => "_start",
+ };
+}