authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-10-29 18:04:11-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-10-29 18:15:09-04:00
log0834e696f75d8477e5bc7a2dc49e7d10800039bc
tree4bc63d8cf74e7fd9dfe7ab06bde9dd16bba62306
parent40901440a620caf1849c627cff0d3a96eda273f5

Elf2: start implementing dynamic linking


11 files changed, 624 insertions(+), 225 deletions(-)

lib/std/Build/Module.zig+7-4
......@@ -596,10 +596,13 @@ pub fn appendZigProcessFlags(
596596 "-target", try target.query.zigTriple(b.allocator),
597597 "-mcpu", try target.query.serializeCpuAlloc(b.allocator),
598598 });
599
600 if (target.query.dynamic_linker.get()) |dynamic_linker| {
601 try zig_args.append("--dynamic-linker");
602 try zig_args.append(dynamic_linker);
599 if (target.query.dynamic_linker) |dynamic_linker| {
600 if (dynamic_linker.get()) |dynamic_linker_path| {
601 try zig_args.append("--dynamic-linker");
602 try zig_args.append(dynamic_linker_path);
603 } else {
604 try zig_args.append("--no-dynamic-linker");
605 }
603606 }
604607 }
605608 }
lib/std/Target/Query.zig+12-5
......@@ -46,8 +46,9 @@ android_api_level: ?u32 = null,
4646abi: ?Target.Abi = null,
4747
4848/// When `os_tag` is `null`, then `null` means native. Otherwise it means the standard path
49/// based on the `os_tag`.
50dynamic_linker: Target.DynamicLinker = .none,
49/// based on the `os_tag`. When `dynamic_linker` is a non-`null` empty string, no dynamic
50/// linker is used regardless of `os_tag`.
51dynamic_linker: ?Target.DynamicLinker = null,
5152
5253/// `null` means default for the cpu/arch/os combo.
5354ofmt: ?Target.ObjectFormat = null,
......@@ -213,7 +214,7 @@ pub fn parse(args: ParseOptions) !Query {
213214 const diags = args.diagnostics orelse &dummy_diags;
214215
215216 var result: Query = .{
216 .dynamic_linker = Target.DynamicLinker.init(args.dynamic_linker),
217 .dynamic_linker = if (args.dynamic_linker) |dynamic_linker| .init(dynamic_linker) else null,
217218 };
218219
219220 var it = mem.splitScalar(u8, args.arch_os_abi, '-');
......@@ -381,7 +382,7 @@ pub fn isNativeCpu(self: Query) bool {
381382
382383pub fn isNativeOs(self: Query) bool {
383384 return self.os_tag == null and self.os_version_min == null and self.os_version_max == null and
384 self.dynamic_linker.get() == null and self.glibc_version == null and self.android_api_level == null;
385 self.dynamic_linker == null and self.glibc_version == null and self.android_api_level == null;
385386}
386387
387388pub fn isNativeAbi(self: Query) bool {
......@@ -599,7 +600,7 @@ pub fn eql(a: Query, b: Query) bool {
599600 if (!versionEqualOpt(a.glibc_version, b.glibc_version)) return false;
600601 if (a.android_api_level != b.android_api_level) return false;
601602 if (a.abi != b.abi) return false;
602 if (!a.dynamic_linker.eql(b.dynamic_linker)) return false;
603 if (!dynamicLinkerEqualOpt(a.dynamic_linker, b.dynamic_linker)) return false;
603604 if (a.ofmt != b.ofmt) return false;
604605
605606 return true;
......@@ -611,6 +612,12 @@ fn versionEqualOpt(a: ?SemanticVersion, b: ?SemanticVersion) bool {
611612 return SemanticVersion.order(a.?, b.?) == .eq;
612613}
613614
615fn dynamicLinkerEqualOpt(a: ?Target.DynamicLinker, b: ?Target.DynamicLinker) bool {
616 if (a == null and b == null) return true;
617 if (a == null or b == null) return false;
618 return a.?.eql(b.?);
619}
620
614621test parse {
615622 const io = std.testing.io;
616623
lib/std/c.zig+2-1
......@@ -7013,7 +7013,8 @@ pub const RTLD = switch (native_os) {
70137013 LAZY: bool = false,
70147014 NOW: bool = false,
70157015 NOLOAD: bool = false,
7016 _3: u5 = 0,
7016 DEEPBIND: bool = false,
7017 _4: u4 = 0,
70177018 GLOBAL: bool = false,
70187019 _9: u3 = 0,
70197020 NODELETE: bool = false,
lib/std/start.zig+1-1
......@@ -562,7 +562,7 @@ fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.c) noreturn {
562562 // Apply the initial relocations as early as possible in the startup process. We cannot
563563 // make calls yet on some architectures (e.g. MIPS) *because* they haven't been applied yet,
564564 // so this must be fully inlined.
565 if (builtin.position_independent_executable) {
565 if (builtin.link_mode == .static and builtin.position_independent_executable) {
566566 @call(.always_inline, std.pie.relocate, .{phdrs});
567567 }
568568
lib/std/zig/system.zig+4-7
......@@ -585,10 +585,10 @@ fn abiAndDynamicLinkerFromFile(
585585 .os = os,
586586 .abi = query.abi orelse Target.Abi.default(cpu.arch, os.tag),
587587 .ofmt = query.ofmt orelse Target.ObjectFormat.default(os.tag, cpu.arch),
588 .dynamic_linker = query.dynamic_linker,
588 .dynamic_linker = query.dynamic_linker orelse .none,
589589 };
590590 var rpath_offset: ?u64 = null; // Found inside PT_DYNAMIC
591 const look_for_ld = query.dynamic_linker.get() == null;
591 const look_for_ld = query.dynamic_linker == null;
592592
593593 var got_dyn_section: bool = false;
594594 {
......@@ -938,7 +938,7 @@ fn detectAbiAndDynamicLinker(io: Io, cpu: Target.Cpu, os: Target.Os, query: Targ
938938 const is_linux = builtin.target.os.tag == .linux;
939939 const is_illumos = builtin.target.os.tag == .illumos;
940940 const is_darwin = builtin.target.os.tag.isDarwin();
941 const have_all_info = query.dynamic_linker.get() != null and
941 const have_all_info = query.dynamic_linker != null and
942942 query.abi != null and (!is_linux or query.abi.?.isGnu());
943943 const os_is_non_native = query.os_tag != null;
944944 // The illumos environment is always the same.
......@@ -1126,10 +1126,7 @@ fn defaultAbiAndDynamicLinker(cpu: Target.Cpu, os: Target.Os, query: Target.Quer
11261126 .os = os,
11271127 .abi = abi,
11281128 .ofmt = query.ofmt orelse Target.ObjectFormat.default(os.tag, cpu.arch),
1129 .dynamic_linker = if (query.dynamic_linker.get() == null)
1130 Target.DynamicLinker.standard(cpu, os, abi)
1131 else
1132 query.dynamic_linker,
1129 .dynamic_linker = query.dynamic_linker orelse .standard(cpu, os, abi),
11331130 };
11341131}
11351132
src/Compilation/Config.zig+24-7
......@@ -123,6 +123,7 @@ pub const ResolveError = error{
123123 WasiExecModelRequiresWasi,
124124 SharedMemoryIsWasmOnly,
125125 ObjectFilesCannotShareMemory,
126 ObjectFilesCannotSpecifyDynamicLinker,
126127 SharedMemoryRequiresAtomicsAndBulkMemory,
127128 ThreadsRequireSharedMemory,
128129 EmittingLlvmModuleRequiresLlvmBackend,
......@@ -131,6 +132,7 @@ pub const ResolveError = error{
131132 EmittingBinaryRequiresLlvmLibrary,
132133 LldIncompatibleObjectFormat,
133134 LldCannotIncrementallyLink,
135 LldCannotSpecifyDynamicLinkerForSharedLibraries,
134136 LtoRequiresLld,
135137 SanitizeThreadRequiresLibCpp,
136138 LibCRequiresLibUnwind,
......@@ -142,6 +144,7 @@ pub const ResolveError = error{
142144 TargetCannotStaticLinkExecutables,
143145 LibCRequiresDynamicLinking,
144146 SharedLibrariesRequireDynamicLinking,
147 DynamicLinkingWithLldRequiresSharedLibraries,
145148 ExportMemoryAndDynamicIncompatible,
146149 DynamicLibraryPrecludesPie,
147150 TargetRequiresPie,
......@@ -274,16 +277,11 @@ pub fn resolve(options: Options) ResolveError!Config {
274277 if (options.link_mode == .static) return error.LibCRequiresDynamicLinking;
275278 break :b .dynamic;
276279 }
277 // When creating a executable that links to system libraries, we
278 // require dynamic linking, but we must not link static libraries
279 // or object files dynamically!
280 if (options.any_dyn_libs and options.output_mode == .Exe) {
281 if (options.link_mode == .static) return error.SharedLibrariesRequireDynamicLinking;
282 break :b .dynamic;
283 }
284280
285281 if (options.link_mode) |link_mode| break :b link_mode;
286282
283 if (options.any_dyn_libs) break :b .dynamic;
284
287285 if (explicitly_exe_or_dyn_lib and link_libc) {
288286 // When using the native glibc/musl ABI, dynamic linking is usually what people want.
289287 if (options.resolved_target.is_native_abi and (target.isGnuLibC() or target.isMuslLibC())) {
......@@ -425,6 +423,25 @@ pub fn resolve(options: Options) ResolveError!Config {
425423 break :b use_llvm;
426424 };
427425
426 switch (options.output_mode) {
427 .Exe => if (options.any_dyn_libs) {
428 // When creating a executable that links to system libraries, we
429 // require dynamic linking, but we must not link static libraries
430 // or object files dynamically!
431 if (link_mode == .static) return error.SharedLibrariesRequireDynamicLinking;
432 } else if (use_lld and !link_libc and !link_libcpp and !link_libunwind) {
433 // Lld does not support creating dynamic executables when not
434 // linking to any shared libraries.
435 if (link_mode == .dynamic) return error.DynamicLinkingWithLldRequiresSharedLibraries;
436 },
437 .Lib => if (use_lld and options.resolved_target.is_explicit_dynamic_linker) {
438 return error.LldCannotSpecifyDynamicLinkerForSharedLibraries;
439 },
440 .Obj => if (options.resolved_target.is_explicit_dynamic_linker) {
441 return error.ObjectFilesCannotSpecifyDynamicLinker;
442 },
443 }
444
428445 const use_new_linker = b: {
429446 if (use_lld) {
430447 if (options.use_new_linker == true) return error.NewLinkerIncompatibleWithLld;
src/codegen/x86_64/Emit.zig+9-3
......@@ -182,6 +182,10 @@ pub fn emitMir(emit: *Emit) Error!void {
182182 try elf_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null)
183183 else if (emit.bin_file.cast(.elf2)) |elf| @intFromEnum(try elf.globalSymbol(.{
184184 .name = extern_func.toSlice(&emit.lower.mir).?,
185 .lib_name = switch (comp.compiler_rt_strat) {
186 .none, .lib, .obj, .zcu => null,
187 .dyn_lib => "compiler_rt",
188 },
185189 .type = .FUNC,
186190 })) else if (emit.bin_file.cast(.macho)) |macho_file|
187191 try macho_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null)
......@@ -320,10 +324,12 @@ pub fn emitMir(emit: *Emit) Error!void {
320324 }, emit.lower.target), &.{.{
321325 .op_index = 0,
322326 .target = .{
323 .index = if (emit.bin_file.cast(.elf)) |elf_file|
324 try elf_file.getGlobalSymbol("__tls_get_addr", null)
325 else if (emit.bin_file.cast(.elf2)) |elf| @intFromEnum(try elf.globalSymbol(.{
327 .index = if (emit.bin_file.cast(.elf)) |elf_file| try elf_file.getGlobalSymbol(
328 "__tls_get_addr",
329 if (comp.config.link_libc) "c" else null,
330 ) else if (emit.bin_file.cast(.elf2)) |elf| @intFromEnum(try elf.globalSymbol(.{
326331 .name = "__tls_get_addr",
332 .lib_name = if (comp.config.link_libc) "c" else null,
327333 .type = .FUNC,
328334 })) else unreachable,
329335 .is_extern = true,
src/link/Elf.zig+11-7
......@@ -1882,17 +1882,13 @@ fn initSyntheticSections(self: *Elf) !void {
18821882 const comp = self.base.comp;
18831883 const target = self.getTarget();
18841884 const ptr_size = self.ptrWidthBytes();
1885 const shared_objects = self.shared_objects.values();
18861885
18871886 const is_exe_or_dyn_lib = switch (comp.config.output_mode) {
18881887 .Exe => true,
18891888 .Lib => comp.config.link_mode == .dynamic,
18901889 .Obj => false,
18911890 };
1892 const have_dynamic_linker = comp.config.link_mode == .dynamic and is_exe_or_dyn_lib and !target.dynamic_linker.eql(.none);
1893
1894 const needs_interp = have_dynamic_linker and
1895 (comp.config.link_libc or comp.root_mod.resolved_target.is_explicit_dynamic_linker);
1891 const have_dynamic_linker = comp.config.link_mode == .dynamic and is_exe_or_dyn_lib;
18961892
18971893 const needs_eh_frame = blk: {
18981894 if (self.zigObjectPtr()) |zo|
......@@ -2004,7 +2000,15 @@ fn initSyntheticSections(self: *Elf) !void {
20042000 });
20052001 }
20062002
2007 if (needs_interp and self.section_indexes.interp == null) {
2003 if (needs_interp: {
2004 if (comp.config.link_mode == .static) break :needs_interp false;
2005 if (target.dynamic_linker.get() == null) break :needs_interp false;
2006 break :needs_interp switch (comp.config.output_mode) {
2007 .Exe => true,
2008 .Lib => comp.root_mod.resolved_target.is_explicit_dynamic_linker,
2009 .Obj => false,
2010 };
2011 } and self.section_indexes.interp == null) {
20082012 self.section_indexes.interp = try self.addSection(.{
20092013 .name = try self.insertShString(".interp"),
20102014 .type = elf.SHT_PROGBITS,
......@@ -2013,7 +2017,7 @@ fn initSyntheticSections(self: *Elf) !void {
20132017 });
20142018 }
20152019
2016 if (self.isEffectivelyDynLib() or shared_objects.len > 0 or comp.config.pie) {
2020 if (have_dynamic_linker or comp.config.pie or self.isEffectivelyDynLib()) {
20172021 if (self.section_indexes.dynstrtab == null) {
20182022 self.section_indexes.dynstrtab = try self.addSection(.{
20192023 .name = try self.insertShString(".dynstr"),
src/link/Elf2.zig+527-178
......@@ -1,11 +1,16 @@
11base: link.File,
2options: link.File.OpenOptions,
23mf: MappedFile,
3known: Node.Known,
4ni: Node.Known,
45nodes: std.MultiArrayList(Node),
56phdrs: std.ArrayList(MappedFile.Node.Index),
7si: Symbol.Known,
68symtab: std.ArrayList(Symbol),
79shstrtab: StringTable,
810strtab: StringTable,
11dynsym: std.ArrayList(Symbol.Index),
12dynstr: StringTable,
13needed: std.AutoArrayHashMapUnmanaged(u32, void),
914inputs: std.ArrayList(struct {
1015 path: std.Build.Cache.Path,
1116 member: ?[]const u8,
......@@ -143,13 +148,13 @@ pub const Node = union(enum) {
143148 };
144149
145150 pub const Known = struct {
146 pub const rodata: MappedFile.Node.Index = @enumFromInt(1);
147 pub const ehdr: MappedFile.Node.Index = @enumFromInt(2);
148 pub const phdr: MappedFile.Node.Index = @enumFromInt(3);
149 pub const shdr: MappedFile.Node.Index = @enumFromInt(4);
150 pub const text: MappedFile.Node.Index = @enumFromInt(5);
151 pub const data: MappedFile.Node.Index = @enumFromInt(6);
152
151 comptime file: MappedFile.Node.Index = .root,
152 comptime ehdr: MappedFile.Node.Index = @enumFromInt(1),
153 comptime shdr: MappedFile.Node.Index = @enumFromInt(2),
154 comptime rodata: MappedFile.Node.Index = @enumFromInt(3),
155 comptime phdr: MappedFile.Node.Index = @enumFromInt(4),
156 comptime text: MappedFile.Node.Index = @enumFromInt(5),
157 comptime data: MappedFile.Node.Index = @enumFromInt(6),
153158 tls: MappedFile.Node.Index,
154159 };
155160
......@@ -231,7 +236,6 @@ pub const Symbol = struct {
231236 rodata,
232237 text,
233238 data,
234 tdata,
235239 _,
236240
237241 pub fn get(si: Symbol.Index, elf: *Elf) *Symbol {
......@@ -250,6 +254,7 @@ pub const Symbol = struct {
250254
251255 pub const InitOptions = struct {
252256 name: []const u8 = "",
257 lib_name: ?[]const u8 = null,
253258 value: u64 = 0,
254259 size: u64 = 0,
255260 type: std.elf.STT,
......@@ -258,29 +263,45 @@ pub const Symbol = struct {
258263 shndx: std.elf.Section = std.elf.SHN_UNDEF,
259264 };
260265 pub fn init(si: Symbol.Index, elf: *Elf, opts: InitOptions) !void {
261 const name_entry = try elf.string(.strtab, opts.name);
262 try Symbol.Index.symtab.node(elf).resize(
263 &elf.mf,
264 elf.base.comp.gpa,
265 @as(usize, switch (elf.identClass()) {
266 .NONE, _ => unreachable,
267 .@"32" => @sizeOf(std.elf.Elf32.Sym),
268 .@"64" => @sizeOf(std.elf.Elf64.Sym),
269 }) * elf.symtab.items.len,
270 );
266 const gpa = elf.base.comp.gpa;
267 const target_endian = elf.targetEndian();
268 const sym_size: usize = switch (elf.identClass()) {
269 .NONE, _ => unreachable,
270 inline else => |class| @sizeOf(class.ElfN().Sym),
271 };
272 const name_strtab_entry = try elf.string(.strtab, opts.name);
273 try elf.si.symtab.node(elf).resize(&elf.mf, gpa, sym_size * elf.symtab.items.len);
271274 switch (elf.symPtr(si)) {
272 inline else => |sym| sym.* = .{
273 .name = name_entry,
274 .value = @intCast(opts.value),
275 .size = @intCast(opts.size),
276 .info = .{
277 .type = opts.type,
278 .bind = opts.bind,
279 },
280 .other = .{
281 .visibility = opts.visibility,
282 },
283 .shndx = opts.shndx,
275 inline else => |sym, class| {
276 sym.* = .{
277 .name = name_strtab_entry,
278 .value = @intCast(opts.value),
279 .size = @intCast(opts.size),
280 .info = .{ .type = opts.type, .bind = opts.bind },
281 .other = .{ .visibility = opts.visibility },
282 .shndx = opts.shndx,
283 };
284 if (target_endian != native_endian) std.mem.byteSwapAllFields(class.ElfN().Sym, sym);
285 },
286 }
287 if (opts.bind == .LOCAL or elf.si.dynsym == .null) return;
288 const dsi = elf.dynsym.items.len;
289 try elf.dynsym.append(gpa, si);
290 const dynsym_ni = elf.si.dynsym.node(elf);
291 const name_dynstr_entry = try elf.string(.dynstr, opts.name);
292 try dynsym_ni.resize(&elf.mf, gpa, sym_size * elf.dynsym.items.len);
293 switch (elf.dynsymSlice()) {
294 inline else => |dynsym, class| {
295 const dsym = &dynsym[dsi];
296 dsym.* = .{
297 .name = name_dynstr_entry,
298 .value = @intCast(opts.value),
299 .size = @intCast(opts.size),
300 .info = .{ .type = opts.type, .bind = opts.bind },
301 .other = .{ .visibility = opts.visibility },
302 .shndx = opts.shndx,
303 };
304 if (target_endian != native_endian) std.mem.byteSwapAllFields(class.ElfN().Sym, dsym);
284305 },
285306 }
286307 }
......@@ -329,6 +350,19 @@ pub const Symbol = struct {
329350 }
330351 };
331352
353 pub const Known = struct {
354 comptime symtab: Symbol.Index = .symtab,
355 comptime shstrtab: Symbol.Index = .shstrtab,
356 comptime strtab: Symbol.Index = .strtab,
357 comptime rodata: Symbol.Index = .rodata,
358 comptime text: Symbol.Index = .text,
359 comptime data: Symbol.Index = .data,
360 dynsym: Symbol.Index,
361 dynstr: Symbol.Index,
362 dynamic: Symbol.Index,
363 tdata: Symbol.Index,
364 };
365
332366 comptime {
333367 if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Symbol) == 16);
334368 }
......@@ -349,6 +383,22 @@ pub const Reloc = extern struct {
349383 AARCH64: std.elf.R_AARCH64,
350384 RISCV: std.elf.R_RISCV,
351385 PPC64: std.elf.R_PPC64,
386
387 pub fn absAddr(elf: *Elf) Reloc.Type {
388 return switch (elf.ehdrField(.machine)) {
389 else => unreachable,
390 .AARCH64 => .{ .AARCH64 = .ABS64 },
391 .PPC64 => .{ .PPC64 = .ADDR64 },
392 .RISCV => .{ .RISCV = .@"64" },
393 .X86_64 => .{ .X86_64 = .@"64" },
394 };
395 }
396 pub fn sizeAddr(elf: *Elf) Reloc.Type {
397 return switch (elf.ehdrField(.machine)) {
398 else => unreachable,
399 .X86_64 => .{ .X86_64 = .SIZE64 },
400 };
401 }
352402 };
353403
354404 pub const Index = enum(u32) {
......@@ -411,7 +461,7 @@ pub const Reloc = extern struct {
411461 ),
412462 .TPOFF32 => {
413463 const phdr = @field(elf.phdrSlice(), @tagName(class));
414 const ph = &phdr[elf.getNode(elf.known.tls).segment];
464 const ph = &phdr[elf.getNode(elf.ni.tls).segment];
415465 assert(elf.targetLoad(&ph.type) == std.elf.PT_TLS);
416466 std.mem.writeInt(
417467 i32,
......@@ -420,6 +470,18 @@ pub const Reloc = extern struct {
420470 target_endian,
421471 );
422472 },
473 .SIZE32 => std.mem.writeInt(
474 u32,
475 loc_slice[0..4],
476 @intCast(elf.targetLoad(&target_sym.size)),
477 target_endian,
478 ),
479 .SIZE64 => std.mem.writeInt(
480 u64,
481 loc_slice[0..8],
482 @intCast(elf.targetLoad(&target_sym.size)),
483 target_endian,
484 ),
423485 },
424486 }
425487 },
......@@ -469,7 +531,6 @@ fn create(
469531 path: std.Build.Cache.Path,
470532 options: link.File.OpenOptions,
471533) !*Elf {
472 _ = options;
473534 const target = &comp.root_mod.resolved_target.result;
474535 assert(target.ofmt == .elf);
475536 const class: std.elf.CLASS = switch (target.ptrBitWidth()) {
......@@ -502,12 +563,16 @@ fn create(
502563 .Obj => .REL,
503564 };
504565 const machine = target.toElfMachine();
505 const maybe_interp = switch (comp.config.output_mode) {
506 .Exe, .Lib => switch (comp.config.link_mode) {
507 .static => null,
508 .dynamic => target.dynamic_linker.get(),
566 const maybe_interp = switch (comp.config.link_mode) {
567 .static => null,
568 .dynamic => switch (comp.config.output_mode) {
569 .Exe => target.dynamic_linker.get(),
570 .Lib => if (comp.root_mod.resolved_target.is_explicit_dynamic_linker)
571 target.dynamic_linker.get()
572 else
573 null,
574 .Obj => null,
509575 },
510 .Obj => null,
511576 };
512577
513578 const elf = try arena.create(Elf);
......@@ -530,12 +595,19 @@ fn create(
530595 .allow_shlib_undefined = false,
531596 .stack_size = 0,
532597 },
598 .options = options,
533599 .mf = try .init(file, comp.gpa),
534 .known = .{
600 .ni = .{
535601 .tls = .none,
536602 },
537603 .nodes = .empty,
538604 .phdrs = .empty,
605 .si = .{
606 .dynsym = .null,
607 .dynstr = .null,
608 .dynamic = .null,
609 .tdata = .null,
610 },
539611 .symtab = .empty,
540612 .shstrtab = .{
541613 .map = .empty,
......@@ -545,6 +617,12 @@ fn create(
545617 .map = .empty,
546618 .size = 1,
547619 },
620 .dynsym = .empty,
621 .dynstr = .{
622 .map = .empty,
623 .size = 1,
624 },
625 .needed = .empty,
548626 .inputs = .empty,
549627 .input_sections = .empty,
550628 .input_section_pending_index = 0,
......@@ -576,6 +654,9 @@ pub fn deinit(elf: *Elf) void {
576654 elf.symtab.deinit(gpa);
577655 elf.shstrtab.map.deinit(gpa);
578656 elf.strtab.map.deinit(gpa);
657 elf.dynsym.deinit(gpa);
658 elf.dynstr.map.deinit(gpa);
659 elf.needed.deinit(gpa);
579660 for (elf.inputs.items) |input| if (input.member) |m| gpa.free(m);
580661 elf.inputs.deinit(gpa);
581662 elf.input_sections.deinit(gpa);
......@@ -599,6 +680,13 @@ fn initHeaders(
599680) !void {
600681 const comp = elf.base.comp;
601682 const gpa = comp.gpa;
683 const have_dynamic_section = switch (@"type") {
684 .NONE => unreachable,
685 .REL => false,
686 .EXEC => comp.config.link_mode == .dynamic,
687 .DYN => true,
688 .CORE, _ => unreachable,
689 };
602690 const addr_align: std.mem.Alignment = switch (class) {
603691 .NONE, _ => unreachable,
604692 .@"32" => .@"4",
......@@ -618,37 +706,32 @@ fn initHeaders(
618706 phnum += 1;
619707 const data_phndx = phnum;
620708 phnum += 1;
709 const dynamic_phndx = if (have_dynamic_section) phndx: {
710 defer phnum += 1;
711 break :phndx phnum;
712 } else undefined;
621713 const tls_phndx = if (comp.config.any_non_single_threaded) phndx: {
622714 defer phnum += 1;
623715 break :phndx phnum;
624716 } else undefined;
625717
626 const expected_nodes_len = 5 + phnum * 2;
718 const expected_nodes_len = 5 + phnum * 2 + @as(usize, 2) * @intFromBool(have_dynamic_section);
627719 try elf.nodes.ensureTotalCapacity(gpa, expected_nodes_len);
628720 try elf.phdrs.resize(gpa, phnum);
629721 elf.nodes.appendAssumeCapacity(.file);
630722
631 assert(Node.Known.rodata == try elf.mf.addOnlyChildNode(gpa, .root, .{
632 .alignment = elf.mf.flags.block_size,
633 .fixed = true,
634 .moved = true,
635 .bubbles_moved = false,
636 }));
637 elf.nodes.appendAssumeCapacity(.{ .segment = rodata_phndx });
638 elf.phdrs.items[rodata_phndx] = Node.Known.rodata;
639
640723 switch (class) {
641724 .NONE, _ => unreachable,
642725 inline else => |ct_class| {
643726 const ElfN = ct_class.ElfN();
644 assert(Node.Known.ehdr == try elf.mf.addOnlyChildNode(gpa, Node.Known.rodata, .{
727 assert(elf.ni.ehdr == try elf.mf.addOnlyChildNode(gpa, elf.ni.file, .{
645728 .size = @sizeOf(ElfN.Ehdr),
646729 .alignment = addr_align,
647730 .fixed = true,
648731 }));
649732 elf.nodes.appendAssumeCapacity(.ehdr);
650733
651 const ehdr: *ElfN.Ehdr = @ptrCast(@alignCast(Node.Known.ehdr.slice(&elf.mf)));
734 const ehdr: *ElfN.Ehdr = @ptrCast(@alignCast(elf.ni.ehdr.slice(&elf.mf)));
652735 const EI = std.elf.EI;
653736 @memcpy(ehdr.ident[0..std.elf.MAGIC.len], std.elf.MAGIC);
654737 ehdr.ident[EI.CLASS] = @intFromEnum(class);
......@@ -674,37 +757,47 @@ fn initHeaders(
674757 },
675758 }
676759
677 assert(Node.Known.phdr == try elf.mf.addLastChildNode(gpa, Node.Known.rodata, .{
678 .size = elf.ehdrField(.phentsize) * elf.ehdrField(.phnum),
760 assert(elf.ni.shdr == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{
761 .size = elf.ehdrField(.shentsize) * elf.ehdrField(.shnum),
679762 .alignment = addr_align,
680763 .moved = true,
681764 .resized = true,
765 }));
766 elf.nodes.appendAssumeCapacity(.shdr);
767
768 assert(elf.ni.rodata == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{
769 .alignment = elf.mf.flags.block_size,
770 .moved = true,
682771 .bubbles_moved = false,
683772 }));
684 elf.nodes.appendAssumeCapacity(.{ .segment = phdr_phndx });
685 elf.phdrs.items[phdr_phndx] = Node.Known.phdr;
773 elf.nodes.appendAssumeCapacity(.{ .segment = rodata_phndx });
774 elf.phdrs.items[rodata_phndx] = elf.ni.rodata;
686775
687 assert(Node.Known.shdr == try elf.mf.addLastChildNode(gpa, Node.Known.rodata, .{
688 .size = elf.ehdrField(.shentsize) * elf.ehdrField(.shnum),
776 assert(elf.ni.phdr == try elf.mf.addOnlyChildNode(gpa, elf.ni.rodata, .{
777 .size = elf.ehdrField(.phentsize) * elf.ehdrField(.phnum),
689778 .alignment = addr_align,
779 .moved = true,
780 .resized = true,
781 .bubbles_moved = false,
690782 }));
691 elf.nodes.appendAssumeCapacity(.shdr);
783 elf.nodes.appendAssumeCapacity(.{ .segment = phdr_phndx });
784 elf.phdrs.items[phdr_phndx] = elf.ni.phdr;
692785
693 assert(Node.Known.text == try elf.mf.addLastChildNode(gpa, .root, .{
786 assert(elf.ni.text == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{
694787 .alignment = elf.mf.flags.block_size,
695788 .moved = true,
696789 .bubbles_moved = false,
697790 }));
698791 elf.nodes.appendAssumeCapacity(.{ .segment = text_phndx });
699 elf.phdrs.items[text_phndx] = Node.Known.text;
792 elf.phdrs.items[text_phndx] = elf.ni.text;
700793
701 assert(Node.Known.data == try elf.mf.addLastChildNode(gpa, .root, .{
794 assert(elf.ni.data == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{
702795 .alignment = elf.mf.flags.block_size,
703796 .moved = true,
704797 .bubbles_moved = false,
705798 }));
706799 elf.nodes.appendAssumeCapacity(.{ .segment = data_phndx });
707 elf.phdrs.items[data_phndx] = Node.Known.data;
800 elf.phdrs.items[data_phndx] = elf.ni.data;
708801
709802 var ph_vaddr: u32 = switch (elf.ehdrField(.type)) {
710803 else => 0,
......@@ -723,7 +816,7 @@ fn initHeaders(
723816 const ElfN = ct_class.ElfN();
724817 const target_endian = elf.targetEndian();
725818
726 const phdr: []ElfN.Phdr = @ptrCast(@alignCast(Node.Known.phdr.slice(&elf.mf)));
819 const phdr: []ElfN.Phdr = @ptrCast(@alignCast(elf.ni.phdr.slice(&elf.mf)));
727820 const ph_phdr = &phdr[phdr_phndx];
728821 ph_phdr.* = .{
729822 .type = std.elf.PT_PHDR,
......@@ -733,7 +826,7 @@ fn initHeaders(
733826 .filesz = 0,
734827 .memsz = 0,
735828 .flags = .{ .R = true },
736 .@"align" = @intCast(Node.Known.phdr.alignment(&elf.mf).toByteUnits()),
829 .@"align" = @intCast(elf.ni.phdr.alignment(&elf.mf).toByteUnits()),
737830 };
738831 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_phdr);
739832
......@@ -752,7 +845,7 @@ fn initHeaders(
752845 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_interp);
753846 }
754847
755 _, const rodata_size = Node.Known.rodata.location(&elf.mf).resolve(&elf.mf);
848 _, const rodata_size = elf.ni.rodata.location(&elf.mf).resolve(&elf.mf);
756849 const ph_rodata = &phdr[rodata_phndx];
757850 ph_rodata.* = .{
758851 .type = std.elf.PT_NULL,
......@@ -762,12 +855,12 @@ fn initHeaders(
762855 .filesz = @intCast(rodata_size),
763856 .memsz = @intCast(rodata_size),
764857 .flags = .{ .R = true },
765 .@"align" = @intCast(Node.Known.rodata.alignment(&elf.mf).toByteUnits()),
858 .@"align" = @intCast(elf.ni.rodata.alignment(&elf.mf).toByteUnits()),
766859 };
767860 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_rodata);
768861 ph_vaddr += @intCast(rodata_size);
769862
770 _, const text_size = Node.Known.text.location(&elf.mf).resolve(&elf.mf);
863 _, const text_size = elf.ni.text.location(&elf.mf).resolve(&elf.mf);
771864 const ph_text = &phdr[text_phndx];
772865 ph_text.* = .{
773866 .type = std.elf.PT_NULL,
......@@ -777,12 +870,12 @@ fn initHeaders(
777870 .filesz = @intCast(text_size),
778871 .memsz = @intCast(text_size),
779872 .flags = .{ .R = true, .X = true },
780 .@"align" = @intCast(Node.Known.text.alignment(&elf.mf).toByteUnits()),
873 .@"align" = @intCast(elf.ni.text.alignment(&elf.mf).toByteUnits()),
781874 };
782875 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_text);
783876 ph_vaddr += @intCast(text_size);
784877
785 _, const data_size = Node.Known.data.location(&elf.mf).resolve(&elf.mf);
878 _, const data_size = elf.ni.data.location(&elf.mf).resolve(&elf.mf);
786879 const ph_data = &phdr[data_phndx];
787880 ph_data.* = .{
788881 .type = std.elf.PT_NULL,
......@@ -792,11 +885,26 @@ fn initHeaders(
792885 .filesz = @intCast(data_size),
793886 .memsz = @intCast(data_size),
794887 .flags = .{ .R = true, .W = true },
795 .@"align" = @intCast(Node.Known.data.alignment(&elf.mf).toByteUnits()),
888 .@"align" = @intCast(elf.ni.data.alignment(&elf.mf).toByteUnits()),
796889 };
797890 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_data);
798891 ph_vaddr += @intCast(data_size);
799892
893 if (have_dynamic_section) {
894 const ph_dynamic = &phdr[dynamic_phndx];
895 ph_dynamic.* = .{
896 .type = std.elf.PT_DYNAMIC,
897 .offset = 0,
898 .vaddr = 0,
899 .paddr = 0,
900 .filesz = 0,
901 .memsz = 0,
902 .flags = .{ .R = true, .W = true },
903 .@"align" = @intCast(addr_align.toByteUnits()),
904 };
905 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_dynamic);
906 }
907
800908 if (comp.config.any_non_single_threaded) {
801909 const ph_tls = &phdr[tls_phndx];
802910 ph_tls.* = .{
......@@ -812,7 +920,7 @@ fn initHeaders(
812920 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_tls);
813921 }
814922
815 const sh_null: *ElfN.Shdr = @ptrCast(@alignCast(Node.Known.shdr.slice(&elf.mf)));
923 const sh_null: *ElfN.Shdr = @ptrCast(@alignCast(elf.ni.shdr.slice(&elf.mf)));
816924 sh_null.* = .{
817925 .name = try elf.string(.shstrtab, ""),
818926 .type = std.elf.SHT_NULL,
......@@ -834,99 +942,142 @@ fn initHeaders(
834942 .target_relocs = .none,
835943 .unused = 0,
836944 };
837 assert(try elf.addSection(Node.Known.rodata, .{
945 assert(elf.si.symtab == try elf.addSection(elf.ni.file, .{
838946 .type = std.elf.SHT_SYMTAB,
947 .size = @sizeOf(ElfN.Sym) * 1,
839948 .addralign = addr_align,
840949 .entsize = @sizeOf(ElfN.Sym),
841 }) == .symtab);
842
843 const symtab: *ElfN.Sym = @ptrCast(@alignCast(Symbol.Index.symtab.node(elf).slice(&elf.mf)));
844 symtab.* = .{
950 }));
951 const symtab_null = @field(elf.symPtr(.null), @tagName(ct_class));
952 symtab_null.* = .{
845953 .name = try elf.string(.strtab, ""),
846954 .value = 0,
847955 .size = 0,
848 .info = .{
849 .type = .NOTYPE,
850 .bind = .LOCAL,
851 },
852 .other = .{
853 .visibility = .DEFAULT,
854 },
956 .info = .{ .type = .NOTYPE, .bind = .LOCAL },
957 .other = .{ .visibility = .DEFAULT },
855958 .shndx = std.elf.SHN_UNDEF,
856959 };
960 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Sym, symtab_null);
857961
858962 const ehdr = @field(elf.ehdrPtr(), @tagName(ct_class));
859963 ehdr.shstrndx = ehdr.shnum;
860964 },
861965 }
862 assert(try elf.addSection(Node.Known.rodata, .{
966 assert(elf.si.shstrtab == try elf.addSection(elf.ni.file, .{
863967 .type = std.elf.SHT_STRTAB,
864968 .addralign = elf.mf.flags.block_size,
865969 .entsize = 1,
866 }) == .shstrtab);
970 }));
867971 try elf.renameSection(.symtab, ".symtab");
868972 try elf.renameSection(.shstrtab, ".shstrtab");
869 Symbol.Index.shstrtab.node(elf).slice(&elf.mf)[0] = 0;
973 elf.si.shstrtab.node(elf).slice(&elf.mf)[0] = 0;
870974
871 assert(try elf.addSection(Node.Known.rodata, .{
975 assert(elf.si.strtab == try elf.addSection(elf.ni.file, .{
872976 .name = ".strtab",
873977 .type = std.elf.SHT_STRTAB,
874 .addralign = elf.mf.flags.block_size,
875978 .size = 1,
979 .addralign = elf.mf.flags.block_size,
876980 .entsize = 1,
877 }) == .strtab);
981 }));
878982 try elf.linkSections(.symtab, .strtab);
879 Symbol.Index.strtab.node(elf).slice(&elf.mf)[0] = 0;
983 elf.si.strtab.node(elf).slice(&elf.mf)[0] = 0;
880984
881 assert(try elf.addSection(Node.Known.rodata, .{
985 assert(elf.si.rodata == try elf.addSection(elf.ni.rodata, .{
882986 .name = ".rodata",
883987 .flags = .{ .ALLOC = true },
884988 .addralign = elf.mf.flags.block_size,
885 }) == .rodata);
886 assert(try elf.addSection(Node.Known.text, .{
989 }));
990 assert(elf.si.text == try elf.addSection(elf.ni.text, .{
887991 .name = ".text",
888992 .flags = .{ .ALLOC = true, .EXECINSTR = true },
889993 .addralign = elf.mf.flags.block_size,
890 }) == .text);
891 assert(try elf.addSection(Node.Known.data, .{
994 }));
995 assert(elf.si.data == try elf.addSection(elf.ni.data, .{
892996 .name = ".data",
893997 .flags = .{ .WRITE = true, .ALLOC = true },
894998 .addralign = elf.mf.flags.block_size,
895 }) == .data);
896 if (comp.config.any_non_single_threaded) {
897 try elf.nodes.ensureUnusedCapacity(gpa, 1);
898 elf.known.tls = try elf.mf.addLastChildNode(gpa, Node.Known.rodata, .{
899 .alignment = elf.mf.flags.block_size,
900 .moved = true,
901 });
902 elf.nodes.appendAssumeCapacity(.{ .segment = tls_phndx });
903 elf.phdrs.items[tls_phndx] = elf.known.tls;
904
905 assert(try elf.addSection(elf.known.tls, .{
906 .name = ".tdata",
907 .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true },
908 .addralign = elf.mf.flags.block_size,
909 }) == .tdata);
910 }
999 }));
9111000 if (maybe_interp) |interp| {
912 try elf.nodes.ensureUnusedCapacity(gpa, 1);
913 const interp_ni = try elf.mf.addLastChildNode(gpa, Node.Known.rodata, .{
1001 const interp_ni = try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{
9141002 .size = interp.len + 1,
9151003 .moved = true,
9161004 .resized = true,
1005 .bubbles_moved = false,
9171006 });
9181007 elf.nodes.appendAssumeCapacity(.{ .segment = interp_phndx });
9191008 elf.phdrs.items[interp_phndx] = interp_ni;
9201009
9211010 const sec_interp_si = try elf.addSection(interp_ni, .{
9221011 .name = ".interp",
923 .size = @intCast(interp.len + 1),
9241012 .flags = .{ .ALLOC = true },
1013 .size = @intCast(interp.len + 1),
9251014 });
9261015 const sec_interp = sec_interp_si.node(elf).slice(&elf.mf);
9271016 @memcpy(sec_interp[0..interp.len], interp);
9281017 sec_interp[interp.len] = 0;
9291018 }
1019 if (have_dynamic_section) {
1020 const dynamic_ni = try elf.mf.addLastChildNode(gpa, elf.ni.data, .{
1021 .moved = true,
1022 .bubbles_moved = false,
1023 });
1024 elf.nodes.appendAssumeCapacity(.{ .segment = dynamic_phndx });
1025 elf.phdrs.items[dynamic_phndx] = dynamic_ni;
1026
1027 switch (class) {
1028 .NONE, _ => unreachable,
1029 inline else => |ct_class| {
1030 const ElfN = ct_class.ElfN();
1031 elf.si.dynsym = try elf.addSection(elf.ni.rodata, .{
1032 .name = ".dynsym",
1033 .type = std.elf.SHT_DYNSYM,
1034 .size = @sizeOf(ElfN.Sym) * 1,
1035 .addralign = addr_align,
1036 .entsize = @sizeOf(ElfN.Sym),
1037 });
1038 const dynsym_null = &@field(elf.dynsymSlice(), @tagName(ct_class))[0];
1039 dynsym_null.* = .{
1040 .name = try elf.string(.dynstr, ""),
1041 .value = 0,
1042 .size = 0,
1043 .info = .{ .type = .NOTYPE, .bind = .LOCAL },
1044 .other = .{ .visibility = .DEFAULT },
1045 .shndx = std.elf.SHN_UNDEF,
1046 };
1047 if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(ElfN.Sym, dynsym_null);
1048 },
1049 }
1050 elf.si.dynstr = try elf.addSection(elf.ni.rodata, .{
1051 .name = ".dynstr",
1052 .type = std.elf.SHT_STRTAB,
1053 .size = 1,
1054 .addralign = elf.mf.flags.block_size,
1055 .entsize = 1,
1056 });
1057 elf.si.dynamic = try elf.addSection(dynamic_ni, .{
1058 .name = ".dynamic",
1059 .type = std.elf.SHT_DYNAMIC,
1060 .flags = .{ .ALLOC = true, .WRITE = true },
1061 .addralign = addr_align,
1062 });
1063 try elf.linkSections(elf.si.dynamic, elf.si.dynstr);
1064 try elf.linkSections(elf.si.dynsym, elf.si.dynstr);
1065 }
1066 if (comp.config.any_non_single_threaded) {
1067 elf.ni.tls = try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{
1068 .alignment = elf.mf.flags.block_size,
1069 .moved = true,
1070 .bubbles_moved = false,
1071 });
1072 elf.nodes.appendAssumeCapacity(.{ .segment = tls_phndx });
1073 elf.phdrs.items[tls_phndx] = elf.ni.tls;
1074
1075 elf.si.tdata = try elf.addSection(elf.ni.tls, .{
1076 .name = ".tdata",
1077 .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true },
1078 .addralign = elf.mf.flags.block_size,
1079 });
1080 }
9301081 assert(elf.nodes.len == expected_nodes_len);
9311082}
9321083
......@@ -962,7 +1113,8 @@ fn getNode(elf: *const Elf, ni: MappedFile.Node.Index) Node {
9621113fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {
9631114 const parent_vaddr = parent_vaddr: {
9641115 const parent_si = switch (elf.getNode(ni.parent(&elf.mf))) {
965 .file, .ehdr, .shdr => unreachable,
1116 .file => return 0,
1117 .ehdr, .shdr => unreachable,
9661118 .segment => |phndx| break :parent_vaddr switch (elf.phdrSlice()) {
9671119 inline else => |ph| elf.targetLoad(&ph[phndx].vaddr),
9681120 },
......@@ -970,7 +1122,7 @@ fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {
9701122 .input_section => unreachable,
9711123 inline .nav, .uav, .lazy_code, .lazy_const_data => |mi| mi.symbol(elf),
9721124 };
973 break :parent_vaddr switch (elf.symPtr(parent_si)) {
1125 break :parent_vaddr if (parent_si == elf.si.tdata) 0 else switch (elf.symPtr(parent_si)) {
9741126 inline else => |sym| elf.targetLoad(&sym.value),
9751127 };
9761128 };
......@@ -1025,7 +1177,7 @@ pub const EhdrPtr = union(std.elf.CLASS) {
10251177 @"64": *std.elf.Elf64.Ehdr,
10261178};
10271179pub fn ehdrPtr(elf: *Elf) EhdrPtr {
1028 const slice = Node.Known.ehdr.slice(&elf.mf);
1180 const slice = elf.ni.ehdr.slice(&elf.mf);
10291181 return switch (elf.identClass()) {
10301182 .NONE, _ => unreachable,
10311183 inline else => |class| @unionInit(
......@@ -1050,7 +1202,7 @@ pub const PhdrSlice = union(std.elf.CLASS) {
10501202 @"64": []std.elf.Elf64.Phdr,
10511203};
10521204pub fn phdrSlice(elf: *Elf) PhdrSlice {
1053 const slice = Node.Known.phdr.slice(&elf.mf);
1205 const slice = elf.ni.phdr.slice(&elf.mf);
10541206 return switch (elf.identClass()) {
10551207 .NONE, _ => unreachable,
10561208 inline else => |class| @unionInit(
......@@ -1067,7 +1219,7 @@ pub const ShdrSlice = union(std.elf.CLASS) {
10671219 @"64": []std.elf.Elf64.Shdr,
10681220};
10691221pub fn shdrSlice(elf: *Elf) ShdrSlice {
1070 const slice = Node.Known.shdr.slice(&elf.mf);
1222 const slice = elf.ni.shdr.slice(&elf.mf);
10711223 return switch (elf.identClass()) {
10721224 .NONE, _ => unreachable,
10731225 inline else => |class| @unionInit(
......@@ -1084,7 +1236,7 @@ pub const SymtabSlice = union(std.elf.CLASS) {
10841236 @"64": []std.elf.Elf64.Sym,
10851237};
10861238pub fn symtabSlice(elf: *Elf) SymtabSlice {
1087 const slice = Symbol.Index.symtab.node(elf).slice(&elf.mf);
1239 const slice = elf.si.symtab.node(elf).slice(&elf.mf);
10881240 return switch (elf.identClass()) {
10891241 .NONE, _ => unreachable,
10901242 inline else => |class| @unionInit(
......@@ -1106,6 +1258,18 @@ pub fn symPtr(elf: *Elf, si: Symbol.Index) SymPtr {
11061258 };
11071259}
11081260
1261pub fn dynsymSlice(elf: *Elf) SymtabSlice {
1262 const slice = elf.si.dynsym.node(elf).slice(&elf.mf);
1263 return switch (elf.identClass()) {
1264 .NONE, _ => unreachable,
1265 inline else => |class| @unionInit(
1266 SymtabSlice,
1267 @tagName(class),
1268 @ptrCast(@alignCast(slice)),
1269 ),
1270 };
1271}
1272
11091273fn addSymbolAssumeCapacity(elf: *Elf) Symbol.Index {
11101274 defer elf.symtab.addOneAssumeCapacity().* = .{
11111275 .ni = .none,
......@@ -1124,6 +1288,7 @@ fn initSymbolAssumeCapacity(elf: *Elf, opts: Symbol.Index.InitOptions) !Symbol.I
11241288
11251289pub fn globalSymbol(elf: *Elf, opts: struct {
11261290 name: []const u8,
1291 lib_name: ?[]const u8 = null,
11271292 type: std.elf.STT,
11281293 bind: std.elf.STB = .GLOBAL,
11291294 visibility: std.elf.STV = .DEFAULT,
......@@ -1133,6 +1298,7 @@ pub fn globalSymbol(elf: *Elf, opts: struct {
11331298 const global_gop = try elf.globals.getOrPut(gpa, try elf.string(.strtab, opts.name));
11341299 if (!global_gop.found_existing) global_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{
11351300 .name = opts.name,
1301 .lib_name = opts.lib_name,
11361302 .type = opts.type,
11371303 .bind = opts.bind,
11381304 .visibility = opts.visibility,
......@@ -1169,15 +1335,15 @@ fn navType(
11691335 },
11701336 };
11711337}
1172fn namedSection(name: []const u8) ?Symbol.Index {
1338fn namedSection(elf: *const Elf, name: []const u8) ?Symbol.Index {
11731339 if (std.mem.eql(u8, name, ".rodata") or
1174 std.mem.startsWith(u8, name, ".rodata.")) return .rodata;
1340 std.mem.startsWith(u8, name, ".rodata.")) return elf.si.rodata;
11751341 if (std.mem.eql(u8, name, ".text") or
1176 std.mem.startsWith(u8, name, ".text.")) return .text;
1342 std.mem.startsWith(u8, name, ".text.")) return elf.si.text;
11771343 if (std.mem.eql(u8, name, ".data") or
1178 std.mem.startsWith(u8, name, ".data.")) return .data;
1344 std.mem.startsWith(u8, name, ".data.")) return elf.si.data;
11791345 if (std.mem.eql(u8, name, ".tdata") or
1180 std.mem.startsWith(u8, name, ".tdata.")) return .tdata;
1346 std.mem.startsWith(u8, name, ".tdata.")) return elf.si.tdata;
11811347 return null;
11821348}
11831349fn navSection(
......@@ -1186,16 +1352,16 @@ fn navSection(
11861352 nav_fr: @FieldType(@FieldType(InternPool.Nav, "status"), "fully_resolved"),
11871353) Symbol.Index {
11881354 if (nav_fr.@"linksection".toSlice(ip)) |@"linksection"|
1189 if (namedSection(@"linksection")) |si| return si;
1355 if (elf.namedSection(@"linksection")) |si| return si;
11901356 return switch (navType(
11911357 ip,
11921358 .{ .fully_resolved = nav_fr },
11931359 elf.base.comp.config.any_non_single_threaded,
11941360 )) {
11951361 else => unreachable,
1196 .FUNC => .text,
1197 .OBJECT => .data,
1198 .TLS => .tdata,
1362 .FUNC => elf.si.text,
1363 .OBJECT => elf.si.data,
1364 .TLS => elf.si.tdata,
11991365 };
12001366}
12011367fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Node.NavMapIndex {
......@@ -1215,6 +1381,7 @@ pub fn navSymbol(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Symbol.
12151381 const nav = ip.getNav(nav_index);
12161382 if (nav.getExtern(ip)) |@"extern"| return elf.globalSymbol(.{
12171383 .name = @"extern".name.toSlice(ip),
1384 .lib_name = @"extern".lib_name.toSlice(ip),
12181385 .type = navType(ip, nav.status, elf.base.comp.config.any_non_single_threaded),
12191386 .bind = switch (@"extern".linkage) {
12201387 .internal => .LOCAL,
......@@ -1266,7 +1433,6 @@ pub fn loadInput(elf: *Elf, input: link.Input) (std.fs.File.Reader.SizeError ||
12661433 const io = elf.base.comp.io;
12671434 var buf: [4096]u8 = undefined;
12681435 switch (input) {
1269 else => {},
12701436 .object => |object| {
12711437 var fr = object.file.reader(io, &buf);
12721438 elf.loadObject(object.path, null, &fr, .{
......@@ -1284,6 +1450,16 @@ pub fn loadInput(elf: *Elf, input: link.Input) (std.fs.File.Reader.SizeError ||
12841450 else => |e| return e,
12851451 };
12861452 },
1453 .res => unreachable,
1454 .dso => |dso| {
1455 try elf.needed.ensureUnusedCapacity(elf.base.comp.gpa, 1);
1456 var fr = dso.file.reader(io, &buf);
1457 elf.loadDso(dso.path, &fr) catch |err| switch (err) {
1458 error.ReadFailed => return fr.err.?,
1459 else => |e| return e,
1460 };
1461 },
1462 .dso_exact => |dso_exact| try elf.loadDsoExact(dso_exact.name),
12871463 }
12881464}
12891465fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fr: *std.Io.File.Reader) !void {
......@@ -1382,7 +1558,7 @@ fn loadObject(
13821558 return diags.failParse(path, "bad machine", .{});
13831559 if (ehdr.shoff == 0 or ehdr.shnum <= 1) return;
13841560 if (ehdr.shoff + ehdr.shentsize * ehdr.shnum > fl.size)
1385 return diags.failParse(path, "bad section header offset/size", .{});
1561 return diags.failParse(path, "bad section header location", .{});
13861562 if (ehdr.shentsize < @sizeOf(ElfN.Shdr))
13871563 return diags.failParse(path, "unsupported shentsize", .{});
13881564 const sections = try gpa.alloc(struct { shdr: ElfN.Shdr, si: Symbol.Index }, ehdr.shnum);
......@@ -1397,7 +1573,7 @@ fn loadObject(
13971573 switch (section.shdr.type) {
13981574 std.elf.SHT_NULL, std.elf.SHT_NOBITS => {},
13991575 else => if (section.shdr.offset + section.shdr.size > fl.size)
1400 return diags.failParse(path, "bad section offset/size", .{}),
1576 return diags.failParse(path, "bad section location", .{}),
14011577 }
14021578 }
14031579 const shstrtab = shstrtab: {
......@@ -1421,7 +1597,7 @@ fn loadObject(
14211597 std.elf.SHT_PROGBITS, std.elf.SHT_NOBITS => {
14221598 if (section.shdr.name >= shstrtab.len) continue;
14231599 const name = std.mem.sliceTo(shstrtab[section.shdr.name..], 0);
1424 const parent_si = namedSection(name) orelse continue;
1600 const parent_si = elf.namedSection(name) orelse continue;
14251601 const ni = try elf.mf.addLastChildNode(gpa, parent_si.node(elf), .{
14261602 .size = section.shdr.size,
14271603 .alignment = .fromByteUnits(std.math.ceilPowerOfTwoAssert(
......@@ -1598,6 +1774,84 @@ fn loadObject(
15981774 },
15991775 }
16001776}
1777fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *std.Io.File.Reader) !void {
1778 const comp = elf.base.comp;
1779 const diags = &comp.link_diags;
1780 const r = &fr.interface;
1781
1782 log.debug("loadDso({f})", .{path.fmtEscapeString()});
1783 const ident = try r.peek(std.elf.EI.NIDENT);
1784 if (!std.mem.eql(u8, ident, elf.mf.contents[0..std.elf.EI.NIDENT]))
1785 return diags.failParse(path, "bad ident", .{});
1786 const target_endian = elf.targetEndian();
1787 switch (elf.identClass()) {
1788 .NONE, _ => unreachable,
1789 inline else => |class| {
1790 const ElfN = class.ElfN();
1791 const ehdr = try r.peekStruct(ElfN.Ehdr, target_endian);
1792 if (ehdr.type != .DYN) return diags.failParse(path, "unsupported dso type", .{});
1793 if (ehdr.machine != elf.ehdrField(.machine))
1794 return diags.failParse(path, "bad machine", .{});
1795 if (ehdr.phoff == 0 or ehdr.phnum <= 1)
1796 return diags.failParse(path, "no program headers", .{});
1797 try fr.seekTo(ehdr.phoff);
1798 const dynamic_ph = for (0..ehdr.phnum) |_| {
1799 const ph = try r.peekStruct(ElfN.Phdr, target_endian);
1800 try r.discardAll(ehdr.phentsize);
1801 switch (ph.type) {
1802 else => {},
1803 std.elf.PT_DYNAMIC => break ph,
1804 }
1805 } else return diags.failParse(path, "no dynamic segment", .{});
1806 const dynnum = std.math.divExact(
1807 u32,
1808 @intCast(dynamic_ph.filesz),
1809 @sizeOf(ElfN.Addr) * 2,
1810 ) catch return diags.failParse(
1811 path,
1812 "dynamic segment filesz (0x{x}) is not a multiple of entsize (0x{x})",
1813 .{ dynamic_ph.filesz, @sizeOf(ElfN.Addr) * 2 },
1814 );
1815 var strtab: ?ElfN.Addr = null;
1816 var strsz: ?ElfN.Addr = null;
1817 var soname: ?ElfN.Addr = null;
1818 try fr.seekTo(dynamic_ph.offset);
1819 for (0..dynnum) |_| {
1820 const key = try r.takeInt(ElfN.Addr, target_endian);
1821 const value = try r.takeInt(ElfN.Addr, target_endian);
1822 switch (key) {
1823 else => {},
1824 std.elf.DT_STRTAB => strtab = value,
1825 std.elf.DT_STRSZ => strsz = value,
1826 std.elf.DT_SONAME => soname = value,
1827 }
1828 }
1829 if (strtab == null or soname == null)
1830 return elf.loadDsoExact(std.fs.path.basename(path.sub_path));
1831 if (strsz) |size| if (soname.? >= size)
1832 return diags.failParse(path, "bad soname string", .{});
1833 try fr.seekTo(ehdr.phoff);
1834 const ph = for (0..ehdr.phnum) |_| {
1835 const ph = try r.peekStruct(ElfN.Phdr, target_endian);
1836 try r.discardAll(ehdr.phentsize);
1837 switch (ph.type) {
1838 else => {},
1839 std.elf.PT_LOAD => if (strtab.? >= ph.vaddr and
1840 strtab.? + (strsz orelse 0) <= ph.vaddr + ph.filesz) break ph,
1841 }
1842 } else return diags.failParse(path, "strtab not part of a loaded segment", .{});
1843 try fr.seekTo(strtab.? + soname.? - ph.vaddr + ph.offset);
1844 return elf.loadDsoExact(r.peekSentinel(0) catch |err| switch (err) {
1845 error.StreamTooLong => return diags.failParse(path, "soname too lang", .{}),
1846 else => |e| return e,
1847 });
1848 },
1849 }
1850}
1851fn loadDsoExact(elf: *Elf, name: []const u8) !void {
1852 log.debug("loadDsoExact({f})", .{std.zig.fmtString(name)});
1853 try elf.needed.put(elf.base.comp.gpa, try elf.string(.dynstr, name), {});
1854}
16011855
16021856pub fn prelink(elf: *Elf, prog_node: std.Progress.Node) !void {
16031857 _ = prog_node;
......@@ -1624,6 +1878,66 @@ fn prelinkInner(elf: *Elf) !void {
16241878 .member = null,
16251879 .si = si,
16261880 };
1881
1882 if (elf.si.dynamic != .null) switch (elf.identClass()) {
1883 .NONE, _ => unreachable,
1884 inline else => |ct_class| {
1885 const ElfN = ct_class.ElfN();
1886 const needed_len = elf.needed.count();
1887 const dynamic_len = needed_len + @intFromBool(elf.options.soname != null) + 5;
1888 const dynamic_size: u32 = @intCast(@sizeOf(ElfN.Addr) * 2 * dynamic_len);
1889 const dynamic_ni = elf.si.dynamic.node(elf);
1890 try dynamic_ni.resize(&elf.mf, gpa, dynamic_size);
1891 const sec_dynamic = dynamic_ni.slice(&elf.mf);
1892 const dynamic_entries: [][2]ElfN.Addr = @ptrCast(@alignCast(sec_dynamic));
1893 var dynamic_index: usize = 0;
1894 for (
1895 dynamic_entries[dynamic_index..][0..needed_len],
1896 elf.needed.keys(),
1897 ) |*dynamic_entry, needed| dynamic_entry.* = .{ std.elf.DT_NEEDED, needed };
1898 dynamic_index += needed_len;
1899 if (elf.options.soname) |soname| {
1900 dynamic_entries[dynamic_index] = .{ std.elf.DT_SONAME, try elf.string(.dynstr, soname) };
1901 dynamic_index += 1;
1902 }
1903 dynamic_entries[dynamic_index..][0..5].* = .{
1904 .{ std.elf.DT_SYMTAB, 0 },
1905 .{ std.elf.DT_SYMENT, @sizeOf(ElfN.Sym) },
1906 .{ std.elf.DT_STRTAB, 0 },
1907 .{ std.elf.DT_STRSZ, 0 },
1908 .{ std.elf.DT_NULL, 0 },
1909 };
1910 dynamic_index += 5;
1911 assert(dynamic_index == dynamic_len);
1912 if (elf.targetEndian() != native_endian) for (dynamic_entries) |*dynamic_entry|
1913 std.mem.byteSwapAllFields(@TypeOf(dynamic_entry.*), dynamic_entry);
1914
1915 const dynamic_sym = elf.si.dynamic.get(elf);
1916 assert(dynamic_sym.loc_relocs == .none);
1917 dynamic_sym.loc_relocs = @enumFromInt(elf.relocs.items.len);
1918 try elf.addReloc(
1919 elf.si.dynamic,
1920 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 5) + 1),
1921 elf.si.dynsym,
1922 0,
1923 .absAddr(elf),
1924 );
1925 try elf.addReloc(
1926 elf.si.dynamic,
1927 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 3) + 1),
1928 elf.si.dynstr,
1929 0,
1930 .absAddr(elf),
1931 );
1932 try elf.addReloc(
1933 elf.si.dynamic,
1934 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 2) + 1),
1935 elf.si.dynstr,
1936 0,
1937 .sizeAddr(elf),
1938 );
1939 },
1940 };
16271941}
16281942
16291943pub fn getNavVAddr(
......@@ -1649,13 +1963,7 @@ pub fn getVAddr(elf: *Elf, reloc_info: link.File.RelocInfo, target_si: Symbol.In
16491963 reloc_info.offset,
16501964 target_si,
16511965 reloc_info.addend,
1652 switch (elf.ehdrField(.machine)) {
1653 else => unreachable,
1654 .AARCH64 => .{ .AARCH64 = .ABS64 },
1655 .PPC64 => .{ .PPC64 = .ADDR64 },
1656 .RISCV => .{ .RISCV = .@"64" },
1657 .X86_64 => .{ .X86_64 = .@"64" },
1658 },
1966 .absAddr(elf),
16591967 );
16601968 return switch (elf.symPtr(target_si)) {
16611969 inline else => |sym| elf.targetLoad(&sym.value),
......@@ -1665,11 +1973,16 @@ pub fn getVAddr(elf: *Elf, reloc_info: link.File.RelocInfo, target_si: Symbol.In
16651973fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
16661974 name: []const u8 = "",
16671975 type: std.elf.Word = std.elf.SHT_NULL,
1668 size: std.elf.Word = 0,
16691976 flags: std.elf.SHF = .{},
1977 size: std.elf.Word = 0,
16701978 addralign: std.mem.Alignment = .@"1",
16711979 entsize: std.elf.Word = 0,
16721980}) !Symbol.Index {
1981 switch (opts.type) {
1982 std.elf.SHT_NULL => assert(opts.size == 0),
1983 std.elf.SHT_PROGBITS => assert(opts.size > 0),
1984 else => {},
1985 }
16731986 const gpa = elf.base.comp.gpa;
16741987 try elf.nodes.ensureUnusedCapacity(gpa, 1);
16751988 try elf.symtab.ensureUnusedCapacity(gpa, 1);
......@@ -1683,16 +1996,23 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
16831996 break :shndx .{ shndx, elf.targetLoad(&ehdr.shentsize) * shnum };
16841997 },
16851998 };
1686 try Node.Known.shdr.resize(&elf.mf, gpa, shdr_size);
1999 try elf.ni.shdr.resize(&elf.mf, gpa, shdr_size);
16872000 const ni = try elf.mf.addLastChildNode(gpa, segment_ni, .{
16882001 .alignment = opts.addralign,
16892002 .size = opts.size,
1690 .moved = true,
2003 .resized = opts.size > 0,
16912004 });
16922005 const si = elf.addSymbolAssumeCapacity();
16932006 elf.nodes.appendAssumeCapacity(.{ .section = si });
16942007 si.get(elf).ni = ni;
1695 try si.init(elf, .{ .size = opts.size, .type = .SECTION, .shndx = shndx });
2008 const addr = elf.computeNodeVAddr(ni);
2009 const offset = ni.fileLocation(&elf.mf, false).offset;
2010 try si.init(elf, .{
2011 .value = addr,
2012 .size = opts.size,
2013 .type = .SECTION,
2014 .shndx = shndx,
2015 });
16962016 switch (elf.shdrSlice()) {
16972017 inline else => |shdr| {
16982018 const sh = &shdr[shndx];
......@@ -1700,8 +2020,8 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
17002020 .name = shstrtab_entry,
17012021 .type = opts.type,
17022022 .flags = .{ .shf = opts.flags },
1703 .addr = 0,
1704 .offset = 0,
2023 .addr = @intCast(addr),
2024 .offset = @intCast(offset),
17052025 .size = opts.size,
17062026 .link = 0,
17072027 .info = 0,
......@@ -1733,7 +2053,7 @@ fn linkSections(elf: *Elf, si: Symbol.Index, link_si: Symbol.Index) !void {
17332053}
17342054
17352055fn sectionName(elf: *Elf, si: Symbol.Index) [:0]const u8 {
1736 const name = Symbol.Index.shstrtab.node(elf).slice(&elf.mf)[switch (elf.shdrSlice()) {
2056 const name = elf.si.shstrtab.node(elf).slice(&elf.mf)[switch (elf.shdrSlice()) {
17372057 inline else => |shndx, class| elf.targetLoad(
17382058 &shndx[elf.targetLoad(&@field(elf.symPtr(si), @tagName(class)).shndx)].name,
17392059 ),
......@@ -1741,12 +2061,12 @@ fn sectionName(elf: *Elf, si: Symbol.Index) [:0]const u8 {
17412061 return name[0..std.mem.indexOfScalar(u8, name, 0).? :0];
17422062}
17432063
1744fn string(elf: *Elf, comptime section: enum { shstrtab, strtab }, key: []const u8) !u32 {
2064fn string(elf: *Elf, comptime section: enum { shstrtab, strtab, dynstr }, key: []const u8) !u32 {
17452065 if (key.len == 0) return 0;
17462066 return @field(elf, @tagName(section)).get(
17472067 elf.base.comp.gpa,
17482068 &elf.mf,
1749 @field(Symbol.Index, @tagName(section)).node(elf),
2069 @field(elf.si, @tagName(section)).node(elf),
17502070 key,
17512071 );
17522072}
......@@ -2144,7 +2464,7 @@ fn flushUav(
21442464 switch (sym.ni) {
21452465 .none => {
21462466 try elf.nodes.ensureUnusedCapacity(gpa, 1);
2147 const ni = try elf.mf.addLastChildNode(gpa, Symbol.Index.data.node(elf), .{
2467 const ni = try elf.mf.addLastChildNode(gpa, elf.si.data.node(elf), .{
21482468 .alignment = uav_align.toStdMem(),
21492469 .moved = true,
21502470 });
......@@ -2256,9 +2576,9 @@ fn flushInputSection(elf: *Elf, isi: Node.InputSectionIndex) !void {
22562576 return error.EndOfStream;
22572577}
22582578
2259fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
2579fn flushFileOffset(elf: *Elf, ni: MappedFile.Node.Index) !void {
22602580 switch (elf.getNode(ni)) {
2261 .file => unreachable,
2581 else => unreachable,
22622582 .ehdr => assert(ni.fileLocation(&elf.mf, false).offset == 0),
22632583 .shdr => switch (elf.ehdrPtr()) {
22642584 inline else => |ehdr| elf.targetStore(
......@@ -2266,32 +2586,61 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
22662586 @intCast(ni.fileLocation(&elf.mf, false).offset),
22672587 ),
22682588 },
2269 .segment => |phndx| switch (elf.phdrSlice()) {
2270 inline else => |phdr, class| {
2271 const ph = &phdr[phndx];
2272 elf.targetStore(&ph.offset, @intCast(ni.fileLocation(&elf.mf, false).offset));
2273 switch (elf.targetLoad(&ph.type)) {
2274 else => unreachable,
2275 std.elf.PT_NULL, std.elf.PT_LOAD => return,
2276 std.elf.PT_DYNAMIC, std.elf.PT_INTERP => {},
2277 std.elf.PT_PHDR => @field(elf.ehdrPtr(), @tagName(class)).phoff = ph.offset,
2278 std.elf.PT_TLS => {},
2279 }
2280 elf.targetStore(&ph.vaddr, @intCast(elf.computeNodeVAddr(ni)));
2281 ph.paddr = ph.vaddr;
2282 },
2589 .segment => |phndx| {
2590 switch (elf.phdrSlice()) {
2591 inline else => |phdr| elf.targetStore(
2592 &phdr[phndx].offset,
2593 @intCast(ni.fileLocation(&elf.mf, false).offset),
2594 ),
2595 }
2596 var child_it = ni.children(&elf.mf);
2597 while (child_it.next()) |child_ni| try elf.flushFileOffset(child_ni);
22832598 },
22842599 .section => |si| switch (elf.shdrSlice()) {
2285 inline else => |shdr, class| {
2286 const sym = @field(elf.symPtr(si), @tagName(class));
2287 const sh = &shdr[elf.targetLoad(&sym.shndx)];
2288 elf.targetStore(&sh.offset, @intCast(ni.fileLocation(&elf.mf, false).offset));
2289 const flags = elf.targetLoad(&sh.flags).shf;
2290 if (flags.ALLOC) {
2291 elf.targetStore(&sh.addr, @intCast(elf.computeNodeVAddr(ni)));
2292 if (!flags.TLS) sym.value = sh.addr;
2293 }
2294 },
2600 inline else => |shdr, class| elf.targetStore(
2601 &shdr[elf.targetLoad(&@field(elf.symPtr(si), @tagName(class)).shndx)].offset,
2602 @intCast(ni.fileLocation(&elf.mf, false).offset),
2603 ),
2604 },
2605 }
2606}
2607
2608fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
2609 switch (elf.getNode(ni)) {
2610 .file => unreachable,
2611 .ehdr, .shdr => try elf.flushFileOffset(ni),
2612 .segment => |phndx| {
2613 try elf.flushFileOffset(ni);
2614 switch (elf.phdrSlice()) {
2615 inline else => |phdr, class| {
2616 const ph = &phdr[phndx];
2617 switch (elf.targetLoad(&ph.type)) {
2618 else => unreachable,
2619 std.elf.PT_NULL, std.elf.PT_LOAD => return,
2620 std.elf.PT_DYNAMIC, std.elf.PT_INTERP => {},
2621 std.elf.PT_PHDR => @field(elf.ehdrPtr(), @tagName(class)).phoff = ph.offset,
2622 std.elf.PT_TLS => {},
2623 }
2624 elf.targetStore(&ph.vaddr, @intCast(elf.computeNodeVAddr(ni)));
2625 ph.paddr = ph.vaddr;
2626 },
2627 }
2628 },
2629 .section => |si| {
2630 try elf.flushFileOffset(ni);
2631 const addr = elf.computeNodeVAddr(ni);
2632 switch (elf.shdrSlice()) {
2633 inline else => |shdr, class| {
2634 const sym = @field(elf.symPtr(si), @tagName(class));
2635 const sh = &shdr[elf.targetLoad(&sym.shndx)];
2636 const flags = elf.targetLoad(&sh.flags).shf;
2637 if (flags.ALLOC) {
2638 elf.targetStore(&sh.addr, @intCast(addr));
2639 sym.value = sh.addr;
2640 }
2641 },
2642 }
2643 si.flushMoved(elf, addr);
22952644 },
22962645 .input_section => |isi| {
22972646 const old_addr = switch (elf.symPtr(isi.symbol(elf))) {
......@@ -2380,11 +2729,11 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {
23802729 else => unreachable,
23812730 std.elf.SHT_NULL => if (size > 0) elf.targetStore(&sh.type, std.elf.SHT_PROGBITS),
23822731 std.elf.SHT_PROGBITS => if (size == 0) elf.targetStore(&sh.type, std.elf.SHT_NULL),
2383 std.elf.SHT_SYMTAB => elf.targetStore(
2732 std.elf.SHT_SYMTAB, std.elf.SHT_DYNSYM => elf.targetStore(
23842733 &sh.info,
23852734 @intCast(@divExact(size, elf.targetLoad(&sh.entsize))),
23862735 ),
2387 std.elf.SHT_STRTAB => {},
2736 std.elf.SHT_STRTAB, std.elf.SHT_DYNAMIC => {},
23882737 }
23892738 },
23902739 },
src/link/Lld.zig+4-5
......@@ -808,7 +808,6 @@ fn elfLink(lld: *Lld, arena: Allocator) !void {
808808 const link_mode = comp.config.link_mode;
809809 const is_dyn_lib = link_mode == .dynamic and is_lib;
810810 const is_exe_or_dyn_lib = is_dyn_lib or output_mode == .Exe;
811 const have_dynamic_linker = link_mode == .dynamic and is_exe_or_dyn_lib;
812811 const target = &comp.root_mod.resolved_target.result;
813812 const compiler_rt_path: ?Cache.Path = blk: {
814813 if (comp.compiler_rt_lib) |x| break :blk x.full_object_path;
......@@ -1070,12 +1069,12 @@ fn elfLink(lld: *Lld, arena: Allocator) !void {
10701069 }
10711070 }
10721071
1073 if (have_dynamic_linker and
1074 (comp.config.link_libc or comp.root_mod.resolved_target.is_explicit_dynamic_linker))
1075 {
1072 if (output_mode == .Exe and link_mode == .dynamic) {
10761073 if (target.dynamic_linker.get()) |dynamic_linker| {
1077 try argv.append("-dynamic-linker");
1074 try argv.append("--dynamic-linker");
10781075 try argv.append(dynamic_linker);
1076 } else {
1077 try argv.append("--no-dynamic-linker");
10791078 }
10801079 }
10811080
src/main.zig+23-7
......@@ -558,6 +558,7 @@ const usage_build_generic =
558558 \\ --enable-new-dtags Use the new behavior for dynamic tags (RUNPATH)
559559 \\ --disable-new-dtags Use the old behavior for dynamic tags (RPATH)
560560 \\ --dynamic-linker [path] Set the dynamic interpreter path (usually ld.so)
561 \\ --no-dynamic-linker Do not set any dynamic interpreter path
561562 \\ --sysroot [path] Set the system root directory (usually /)
562563 \\ --version [ver] Dynamic library semver
563564 \\ -fentry Enable entry point with default symbol name
......@@ -1301,6 +1302,8 @@ fn buildOutputType(
13011302 mod_opts.optimize_mode = parseOptimizeMode(rest);
13021303 } else if (mem.eql(u8, arg, "--dynamic-linker")) {
13031304 create_module.dynamic_linker = args_iter.nextOrFatal();
1305 } else if (mem.eql(u8, arg, "--no-dynamic-linker")) {
1306 create_module.dynamic_linker = "";
13041307 } else if (mem.eql(u8, arg, "--sysroot")) {
13051308 const next_arg = args_iter.nextOrFatal();
13061309 create_module.sysroot = next_arg;
......@@ -2418,6 +2421,11 @@ fn buildOutputType(
24182421 mem.eql(u8, arg, "-dynamic-linker"))
24192422 {
24202423 create_module.dynamic_linker = linker_args_it.nextOrFatal();
2424 } else if (mem.eql(u8, arg, "-I") or
2425 mem.eql(u8, arg, "--no-dynamic-linker") or
2426 mem.eql(u8, arg, "-no-dynamic-linker"))
2427 {
2428 create_module.dynamic_linker = "";
24212429 } else if (mem.eql(u8, arg, "-E") or
24222430 mem.eql(u8, arg, "--export-dynamic") or
24232431 mem.eql(u8, arg, "-export-dynamic"))
......@@ -3191,13 +3199,14 @@ fn buildOutputType(
31913199 const resolved_soname: ?[]const u8 = switch (soname) {
31923200 .yes => |explicit| explicit,
31933201 .no => null,
3194 .yes_default_value => switch (target.ofmt) {
3195 .elf => if (have_version)
3202 .yes_default_value => if (create_module.resolved_options.output_mode == .Lib and
3203 create_module.resolved_options.link_mode == .dynamic and target.ofmt == .elf)
3204 if (have_version)
31963205 try std.fmt.allocPrint(arena, "lib{s}.so.{d}", .{ root_name, version.major })
31973206 else
3198 try std.fmt.allocPrint(arena, "lib{s}.so", .{root_name}),
3199 else => null,
3200 },
3207 try std.fmt.allocPrint(arena, "lib{s}.so", .{root_name})
3208 else
3209 null,
32013210 };
32023211
32033212 const emit_bin_resolved: Compilation.CreateOptions.Emit = switch (emit_bin) {
......@@ -3646,7 +3655,11 @@ fn buildOutputType(
36463655 try test_exec_args.append(arena, try std.fmt.allocPrint(arena, "-mcpu={s}", .{mcpu}));
36473656 }
36483657 if (create_module.dynamic_linker) |dl| {
3649 try test_exec_args.appendSlice(arena, &.{ "--dynamic-linker", dl });
3658 if (dl.len > 0) {
3659 try test_exec_args.appendSlice(arena, &.{ "--dynamic-linker", dl });
3660 } else {
3661 try test_exec_args.append(arena, "--no-dynamic-linker");
3662 }
36503663 }
36513664 try test_exec_args.append(arena, null); // placeholder for the path of the emitted C source file
36523665 }
......@@ -3793,7 +3806,7 @@ fn createModule(
37933806 .result = target,
37943807 .is_native_os = target_query.isNativeOs(),
37953808 .is_native_abi = target_query.isNativeAbi(),
3796 .is_explicit_dynamic_linker = !target_query.dynamic_linker.eql(.none),
3809 .is_explicit_dynamic_linker = target_query.dynamic_linker != null,
37973810 };
37983811 };
37993812
......@@ -3965,6 +3978,7 @@ fn createModule(
39653978 error.WasiExecModelRequiresWasi => fatal("only WASI OS targets support execution model", .{}),
39663979 error.SharedMemoryIsWasmOnly => fatal("only WebAssembly CPU targets support shared memory", .{}),
39673980 error.ObjectFilesCannotShareMemory => fatal("object files cannot share memory", .{}),
3981 error.ObjectFilesCannotSpecifyDynamicLinker => fatal("object files cannot specify --dynamic-linker", .{}),
39683982 error.SharedMemoryRequiresAtomicsAndBulkMemory => fatal("shared memory requires atomics and bulk_memory CPU features", .{}),
39693983 error.ThreadsRequireSharedMemory => fatal("threads require shared memory", .{}),
39703984 error.EmittingLlvmModuleRequiresLlvmBackend => fatal("emitting an LLVM module requires using the LLVM backend", .{}),
......@@ -3973,6 +3987,7 @@ fn createModule(
39733987 error.EmittingBinaryRequiresLlvmLibrary => fatal("producing machine code via LLVM requires using the LLVM library", .{}),
39743988 error.LldIncompatibleObjectFormat => fatal("using LLD to link {s} files is unsupported", .{@tagName(target.ofmt)}),
39753989 error.LldCannotIncrementallyLink => fatal("self-hosted backends do not support linking with LLD", .{}),
3990 error.LldCannotSpecifyDynamicLinkerForSharedLibraries => fatal("LLD does not support --dynamic-linker on shared libraries", .{}),
39763991 error.LtoRequiresLld => fatal("LTO requires using LLD", .{}),
39773992 error.SanitizeThreadRequiresLibCpp => fatal("thread sanitization is (for now) implemented in C++, so it requires linking libc++", .{}),
39783993 error.LibCRequiresLibUnwind => fatal("libc of the specified target requires linking libunwind", .{}),
......@@ -3984,6 +3999,7 @@ fn createModule(
39843999 error.TargetCannotStaticLinkExecutables => fatal("static linking of executables unavailable on the specified target", .{}),
39854000 error.LibCRequiresDynamicLinking => fatal("libc of the specified target requires dynamic linking", .{}),
39864001 error.SharedLibrariesRequireDynamicLinking => fatal("using shared libraries requires dynamic linking", .{}),
4002 error.DynamicLinkingWithLldRequiresSharedLibraries => fatal("dynamic linking with lld requires at least one shared library", .{}),
39874003 error.ExportMemoryAndDynamicIncompatible => fatal("exporting memory is incompatible with dynamic linking", .{}),
39884004 error.DynamicLibraryPrecludesPie => fatal("dynamic libraries cannot be position independent executables", .{}),
39894005 error.TargetRequiresPie => fatal("the specified target requires position independent executables", .{}),