From 5ae3e4e9bd5216c7cc2305c8996ed413c89c59e7 Mon Sep 17 00:00:00 2001 From: Kenta Iwasaki Date: Sat, 1 Jan 2022 06:32:37 +0900 Subject: [PATCH 1/2] lld: allow for entrypoint symbol name to be set This commit enables for the entrypoint symbol to be set when linking ELF or WebAssembly modules with lld using the Zig compiler. --- lib/std/build.zig | 8 ++++++++ src/Compilation.zig | 2 ++ src/link.zig | 1 + src/link/Coff.zig | 1 + src/link/Elf.zig | 6 ++++++ src/link/MachO.zig | 1 + src/link/Wasm.zig | 6 ++++++ src/main.zig | 13 +++++++++++++ 8 files changed, 38 insertions(+) diff --git a/lib/std/build.zig b/lib/std/build.zig index 09f57a8cfa..47f721c2ba 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -1554,6 +1554,9 @@ pub const LibExeObjStep = struct { subsystem: ?std.Target.SubSystem = null, + /// Entrypoint symbol name + entry: ?[]const u8 = null, + /// Overrides the default stack size stack_size: ?u64 = null, @@ -2255,6 +2258,11 @@ pub const LibExeObjStep = struct { try zig_args.append(@tagName(builder.color)); } + if (self.entry) |entry| { + try zig_args.append("--entry"); + try zig_args.append(entry); + } + if (self.stack_size) |stack_size| { try zig_args.append("--stack"); try zig_args.append(try std.fmt.allocPrint(builder.allocator, "{}", .{stack_size})); diff --git a/src/Compilation.zig b/src/Compilation.zig index c21bf71326..2c64657903 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -791,6 +791,7 @@ pub const InitOptions = struct { /// infinite recursion. skip_linker_dependencies: bool = false, parent_compilation_link_libc: bool = false, + entry: ?[]const u8 = null, stack_size_override: ?u64 = null, image_base_override: ?u64 = null, self_exe_path: ?[]const u8 = null, @@ -1572,6 +1573,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .linker_optimization = linker_optimization, .major_subsystem_version = options.major_subsystem_version, .minor_subsystem_version = options.minor_subsystem_version, + .entry = options.entry, .stack_size_override = options.stack_size_override, .image_base_override = options.image_base_override, .include_compiler_rt = include_compiler_rt, diff --git a/src/link.zig b/src/link.zig index 3dc75c77e8..916dea0429 100644 --- a/src/link.zig +++ b/src/link.zig @@ -84,6 +84,7 @@ pub const Options = struct { /// the binary file does not already have such a section. program_code_size_hint: u64 = 256 * 1024, entry_addr: ?u64 = null, + entry: ?[]const u8, stack_size_override: ?u64, image_base_override: ?u64, cache_mode: CacheMode, diff --git a/src/link/Coff.zig b/src/link/Coff.zig index 26b8c78a28..b6ae8abcb1 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -951,6 +951,7 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void { _ = try man.addFile(key.status.success.object_path, null); } try man.addOptionalFile(module_obj_path); + man.hash.addOptionalBytes(self.base.options.entry); man.hash.addOptional(self.base.options.stack_size_override); man.hash.addOptional(self.base.options.image_base_override); man.hash.addListOfBytes(self.base.options.lib_dirs); diff --git a/src/link/Elf.zig b/src/link/Elf.zig index d0f9d7851d..d675833ef2 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -1396,6 +1396,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { // 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(self.base.options.entry); man.hash.add(stack_size); man.hash.addOptional(self.base.options.image_base_override); man.hash.add(gc_sections); @@ -1518,6 +1519,11 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { self.base.options.linker_optimization, })); + if (self.base.options.entry) |entry| { + try argv.append("--entry"); + try argv.append(entry); + } + if (self.base.options.output_mode == .Exe) { try argv.append("-z"); try argv.append(try std.fmt.allocPrint(arena, "stack-size={d}", .{stack_size})); diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 6335151bef..eaeb5265eb 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -509,6 +509,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { try man.addOptionalFile(module_obj_path); // 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(self.base.options.entry); man.hash.add(stack_size); man.hash.addListOfBytes(self.base.options.lib_dirs); man.hash.addListOfBytes(self.base.options.framework_dirs); diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 34723cdb27..e9ebb669fe 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -1137,6 +1137,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void { } try man.addOptionalFile(module_obj_path); try man.addOptionalFile(compiler_rt_path); + man.hash.addOptionalBytes(self.base.options.entry); man.hash.addOptional(self.base.options.stack_size_override); man.hash.add(self.base.options.import_memory); man.hash.add(self.base.options.import_table); @@ -1295,6 +1296,11 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void { } } + if (self.base.options.entry) |entry| { + try argv.append("--entry"); + try argv.append(entry); + } + if (self.base.options.output_mode == .Exe) { // Increase the default stack size to a more reasonable value of 1MB instead of // the default of 1 Wasm page being 64KB, unless overridden by the user. diff --git a/src/main.zig b/src/main.zig index c924b14b69..3561315989 100644 --- a/src/main.zig +++ b/src/main.zig @@ -400,6 +400,7 @@ const usage_build_generic = \\ --dynamic-linker [path] Set the dynamic interpreter path (usually ld.so) \\ --sysroot [path] Set the system root directory (usually /) \\ --version [ver] Dynamic library semver + \\ --entry [name] Set the entrypoint symbol name \\ -fsoname[=name] Override the default SONAME value \\ -fno-soname Disable emitting a SONAME \\ -fLLD Force using LLD as the linker @@ -647,6 +648,7 @@ fn buildOutputType( var linker_optimization: ?u8 = null; var test_evented_io = false; var test_no_exec = false; + var entry: ?[]const u8 = null; var stack_size_override: ?u64 = null; var image_base_override: ?u64 = null; var use_llvm: ?bool = null; @@ -847,6 +849,10 @@ fn buildOutputType( if (i + 1 >= args.len) fatal("expected parameter after {s}", .{arg}); i += 1; optimize_mode_string = args[i]; + } else if (mem.eql(u8, arg, "--entry")) { + if (i + 1 >= args.len) fatal("expected parameter after {s}", .{arg}); + i += 1; + entry = args[i]; } else if (mem.eql(u8, arg, "--stack")) { if (i + 1 >= args.len) fatal("expected parameter after {s}", .{arg}); i += 1; @@ -1624,6 +1630,12 @@ fn buildOutputType( fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) }); }; have_version = true; + } else if (mem.eql(u8, arg, "-e") or mem.eql(u8, arg, "--entry")) { + i += 1; + if (i >= linker_args.items.len) { + fatal("expected linker arg after '{s}'", .{arg}); + } + entry = linker_args.items[i]; } else if (mem.eql(u8, arg, "--stack")) { i += 1; if (i >= linker_args.items.len) { @@ -2500,6 +2512,7 @@ fn buildOutputType( .minor_subsystem_version = minor_subsystem_version, .link_eh_frame_hdr = link_eh_frame_hdr, .link_emit_relocs = link_emit_relocs, + .entry = entry, .stack_size_override = stack_size_override, .image_base_override = image_base_override, .strip = strip, From fd6d1fe015c62cbdb52c9703384c0321b8c5ef01 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 19 Jan 2022 11:41:08 -0700 Subject: [PATCH 2/2] stage2: improvements to entry point handling * rename `entry` to `entry_symbol_name` for the zig build API * integrate with `zig cc` command line options * integrate with COFF linking with LLD * integrate with self-hosted ELF linker * don't put it in the hash for MachO since it is ignored --- lib/std/build.zig | 5 ++--- src/clang_options_data.zig | 11 +++++++++-- src/link/Coff.zig | 4 ++++ src/link/Elf.zig | 3 ++- src/link/MachO.zig | 1 - src/main.zig | 4 ++++ tools/update_clang_options.zig | 8 ++++++++ 7 files changed, 29 insertions(+), 7 deletions(-) diff --git a/lib/std/build.zig b/lib/std/build.zig index 47f721c2ba..24513c6b2e 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -1554,8 +1554,7 @@ pub const LibExeObjStep = struct { subsystem: ?std.Target.SubSystem = null, - /// Entrypoint symbol name - entry: ?[]const u8 = null, + entry_symbol_name: ?[]const u8 = null, /// Overrides the default stack size stack_size: ?u64 = null, @@ -2258,7 +2257,7 @@ pub const LibExeObjStep = struct { try zig_args.append(@tagName(builder.color)); } - if (self.entry) |entry| { + if (self.entry_symbol_name) |entry| { try zig_args.append("--entry"); try zig_args.append(entry); } diff --git a/src/clang_options_data.zig b/src/clang_options_data.zig index 85ff809761..dbcf0f749f 100644 --- a/src/clang_options_data.zig +++ b/src/clang_options_data.zig @@ -1655,7 +1655,7 @@ flagpsl("MT"), .{ .name = "entry", .syntax = .flag, - .zig_equivalent = .other, + .zig_equivalent = .entry, .pd1 = false, .pd2 = true, .psl = false, @@ -6701,7 +6701,14 @@ joinpd1("Z"), joinpd1("a"), jspd1("b"), joinpd1("d"), -jspd1("e"), +.{ + .name = "e", + .syntax = .joined_or_separate, + .zig_equivalent = .entry, + .pd1 = true, + .pd2 = false, + .psl = false, +}, .{ .name = "l", .syntax = .joined_or_separate, diff --git a/src/link/Coff.zig b/src/link/Coff.zig index b6ae8abcb1..5d24e42fad 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -1071,6 +1071,10 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void { try argv.append("-DLL"); } + if (self.base.options.entry) |entry| { + try argv.append(try allocPrint(arena, "-ENTRY:{s}", .{entry})); + } + if (self.base.options.tsaware) { try argv.append("-tsaware"); } diff --git a/src/link/Elf.zig b/src/link/Elf.zig index d675833ef2..63381d24a4 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -2889,7 +2889,8 @@ pub fn updateDeclExports( const stb_bits: u8 = switch (exp.options.linkage) { .Internal => elf.STB_LOCAL, .Strong => blk: { - if (mem.eql(u8, exp.options.name, "_start")) { + const entry_name = self.base.options.entry orelse "_start"; + if (mem.eql(u8, exp.options.name, entry_name)) { self.entry_addr = decl_sym.st_value; } break :blk elf.STB_GLOBAL; diff --git a/src/link/MachO.zig b/src/link/MachO.zig index eaeb5265eb..6335151bef 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -509,7 +509,6 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { try man.addOptionalFile(module_obj_path); // 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(self.base.options.entry); man.hash.add(stack_size); man.hash.addListOfBytes(self.base.options.lib_dirs); man.hash.addListOfBytes(self.base.options.framework_dirs); diff --git a/src/main.zig b/src/main.zig index 3561315989..9aedb42d38 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1485,6 +1485,9 @@ fn buildOutputType( .sysroot => { sysroot = it.only_arg; }, + .entry => { + entry = it.only_arg; + }, } } // Parse linker args. @@ -4156,6 +4159,7 @@ pub const ClangArgIterator = struct { exec_model, emit_llvm, sysroot, + entry, }; const Args = struct { diff --git a/tools/update_clang_options.zig b/tools/update_clang_options.zig index 73b1bbd284..bada964c91 100644 --- a/tools/update_clang_options.zig +++ b/tools/update_clang_options.zig @@ -416,6 +416,14 @@ const known_options = [_]KnownOpt{ .name = "sysroot", .ident = "sysroot", }, + .{ + .name = "entry", + .ident = "entry", + }, + .{ + .name = "e", + .ident = "entry", + }, }; const blacklisted_options = [_][]const u8{};