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(...@@ -596,10 +596,13 @@ pub fn appendZigProcessFlags(
596 "-target", try target.query.zigTriple(b.allocator),596 "-target", try target.query.zigTriple(b.allocator),
597 "-mcpu", try target.query.serializeCpuAlloc(b.allocator),597 "-mcpu", try target.query.serializeCpuAlloc(b.allocator),
598 });598 });
599599 if (target.query.dynamic_linker) |dynamic_linker| {
600 if (target.query.dynamic_linker.get()) |dynamic_linker| {600 if (dynamic_linker.get()) |dynamic_linker_path| {
601 try zig_args.append("--dynamic-linker");601 try zig_args.append("--dynamic-linker");
602 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 }
603 }606 }
604 }607 }
605 }608 }
lib/std/Target/Query.zig+12-5
...@@ -46,8 +46,9 @@ android_api_level: ?u32 = null,...@@ -46,8 +46,9 @@ android_api_level: ?u32 = null,
46abi: ?Target.Abi = null,46abi: ?Target.Abi = null,
4747
48/// When `os_tag` is `null`, then `null` means native. Otherwise it means the standard path48/// When `os_tag` is `null`, then `null` means native. Otherwise it means the standard path
49/// based on the `os_tag`.49/// based on the `os_tag`. When `dynamic_linker` is a non-`null` empty string, no dynamic
50dynamic_linker: Target.DynamicLinker = .none,50/// linker is used regardless of `os_tag`.
51dynamic_linker: ?Target.DynamicLinker = null,
5152
52/// `null` means default for the cpu/arch/os combo.53/// `null` means default for the cpu/arch/os combo.
53ofmt: ?Target.ObjectFormat = null,54ofmt: ?Target.ObjectFormat = null,
...@@ -213,7 +214,7 @@ pub fn parse(args: ParseOptions) !Query {...@@ -213,7 +214,7 @@ pub fn parse(args: ParseOptions) !Query {
213 const diags = args.diagnostics orelse &dummy_diags;214 const diags = args.diagnostics orelse &dummy_diags;
214215
215 var result: Query = .{216 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,
217 };218 };
218219
219 var it = mem.splitScalar(u8, args.arch_os_abi, '-');220 var it = mem.splitScalar(u8, args.arch_os_abi, '-');
...@@ -381,7 +382,7 @@ pub fn isNativeCpu(self: Query) bool {...@@ -381,7 +382,7 @@ pub fn isNativeCpu(self: Query) bool {
381382
382pub fn isNativeOs(self: Query) bool {383pub fn isNativeOs(self: Query) bool {
383 return self.os_tag == null and self.os_version_min == null and self.os_version_max == null and384 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;
385}386}
386387
387pub fn isNativeAbi(self: Query) bool {388pub fn isNativeAbi(self: Query) bool {
...@@ -599,7 +600,7 @@ pub fn eql(a: Query, b: Query) bool {...@@ -599,7 +600,7 @@ pub fn eql(a: Query, b: Query) bool {
599 if (!versionEqualOpt(a.glibc_version, b.glibc_version)) return false;600 if (!versionEqualOpt(a.glibc_version, b.glibc_version)) return false;
600 if (a.android_api_level != b.android_api_level) return false;601 if (a.android_api_level != b.android_api_level) return false;
601 if (a.abi != b.abi) return false;602 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;
603 if (a.ofmt != b.ofmt) return false;604 if (a.ofmt != b.ofmt) return false;
604605
605 return true;606 return true;
...@@ -611,6 +612,12 @@ fn versionEqualOpt(a: ?SemanticVersion, b: ?SemanticVersion) bool {...@@ -611,6 +612,12 @@ fn versionEqualOpt(a: ?SemanticVersion, b: ?SemanticVersion) bool {
611 return SemanticVersion.order(a.?, b.?) == .eq;612 return SemanticVersion.order(a.?, b.?) == .eq;
612}613}
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
614test parse {621test parse {
615 const io = std.testing.io;622 const io = std.testing.io;
616623
lib/std/c.zig+2-1
...@@ -7013,7 +7013,8 @@ pub const RTLD = switch (native_os) {...@@ -7013,7 +7013,8 @@ pub const RTLD = switch (native_os) {
7013 LAZY: bool = false,7013 LAZY: bool = false,
7014 NOW: bool = false,7014 NOW: bool = false,
7015 NOLOAD: bool = false,7015 NOLOAD: bool = false,
7016 _3: u5 = 0,7016 DEEPBIND: bool = false,
7017 _4: u4 = 0,
7017 GLOBAL: bool = false,7018 GLOBAL: bool = false,
7018 _9: u3 = 0,7019 _9: u3 = 0,
7019 NODELETE: bool = false,7020 NODELETE: bool = false,
lib/std/start.zig+1-1
...@@ -562,7 +562,7 @@ fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.c) noreturn {...@@ -562,7 +562,7 @@ fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.c) noreturn {
562 // Apply the initial relocations as early as possible in the startup process. We cannot562 // Apply the initial relocations as early as possible in the startup process. We cannot
563 // make calls yet on some architectures (e.g. MIPS) *because* they haven't been applied yet,563 // make calls yet on some architectures (e.g. MIPS) *because* they haven't been applied yet,
564 // so this must be fully inlined.564 // so this must be fully inlined.
565 if (builtin.position_independent_executable) {565 if (builtin.link_mode == .static and builtin.position_independent_executable) {
566 @call(.always_inline, std.pie.relocate, .{phdrs});566 @call(.always_inline, std.pie.relocate, .{phdrs});
567 }567 }
568568
lib/std/zig/system.zig+4-7
...@@ -585,10 +585,10 @@ fn abiAndDynamicLinkerFromFile(...@@ -585,10 +585,10 @@ fn abiAndDynamicLinkerFromFile(
585 .os = os,585 .os = os,
586 .abi = query.abi orelse Target.Abi.default(cpu.arch, os.tag),586 .abi = query.abi orelse Target.Abi.default(cpu.arch, os.tag),
587 .ofmt = query.ofmt orelse Target.ObjectFormat.default(os.tag, cpu.arch),587 .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,
589 };589 };
590 var rpath_offset: ?u64 = null; // Found inside PT_DYNAMIC590 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
593 var got_dyn_section: bool = false;593 var got_dyn_section: bool = false;
594 {594 {
...@@ -938,7 +938,7 @@ fn detectAbiAndDynamicLinker(io: Io, cpu: Target.Cpu, os: Target.Os, query: Targ...@@ -938,7 +938,7 @@ fn detectAbiAndDynamicLinker(io: Io, cpu: Target.Cpu, os: Target.Os, query: Targ
938 const is_linux = builtin.target.os.tag == .linux;938 const is_linux = builtin.target.os.tag == .linux;
939 const is_illumos = builtin.target.os.tag == .illumos;939 const is_illumos = builtin.target.os.tag == .illumos;
940 const is_darwin = builtin.target.os.tag.isDarwin();940 const is_darwin = builtin.target.os.tag.isDarwin();
941 const have_all_info = query.dynamic_linker.get() != null and941 const have_all_info = query.dynamic_linker != null and
942 query.abi != null and (!is_linux or query.abi.?.isGnu());942 query.abi != null and (!is_linux or query.abi.?.isGnu());
943 const os_is_non_native = query.os_tag != null;943 const os_is_non_native = query.os_tag != null;
944 // The illumos environment is always the same.944 // The illumos environment is always the same.
...@@ -1126,10 +1126,7 @@ fn defaultAbiAndDynamicLinker(cpu: Target.Cpu, os: Target.Os, query: Target.Quer...@@ -1126,10 +1126,7 @@ fn defaultAbiAndDynamicLinker(cpu: Target.Cpu, os: Target.Os, query: Target.Quer
1126 .os = os,1126 .os = os,
1127 .abi = abi,1127 .abi = abi,
1128 .ofmt = query.ofmt orelse Target.ObjectFormat.default(os.tag, cpu.arch),1128 .ofmt = query.ofmt orelse Target.ObjectFormat.default(os.tag, cpu.arch),
1129 .dynamic_linker = if (query.dynamic_linker.get() == null)1129 .dynamic_linker = query.dynamic_linker orelse .standard(cpu, os, abi),
1130 Target.DynamicLinker.standard(cpu, os, abi)
1131 else
1132 query.dynamic_linker,
1133 };1130 };
1134}1131}
11351132
src/Compilation/Config.zig+24-7
...@@ -123,6 +123,7 @@ pub const ResolveError = error{...@@ -123,6 +123,7 @@ pub const ResolveError = error{
123 WasiExecModelRequiresWasi,123 WasiExecModelRequiresWasi,
124 SharedMemoryIsWasmOnly,124 SharedMemoryIsWasmOnly,
125 ObjectFilesCannotShareMemory,125 ObjectFilesCannotShareMemory,
126 ObjectFilesCannotSpecifyDynamicLinker,
126 SharedMemoryRequiresAtomicsAndBulkMemory,127 SharedMemoryRequiresAtomicsAndBulkMemory,
127 ThreadsRequireSharedMemory,128 ThreadsRequireSharedMemory,
128 EmittingLlvmModuleRequiresLlvmBackend,129 EmittingLlvmModuleRequiresLlvmBackend,
...@@ -131,6 +132,7 @@ pub const ResolveError = error{...@@ -131,6 +132,7 @@ pub const ResolveError = error{
131 EmittingBinaryRequiresLlvmLibrary,132 EmittingBinaryRequiresLlvmLibrary,
132 LldIncompatibleObjectFormat,133 LldIncompatibleObjectFormat,
133 LldCannotIncrementallyLink,134 LldCannotIncrementallyLink,
135 LldCannotSpecifyDynamicLinkerForSharedLibraries,
134 LtoRequiresLld,136 LtoRequiresLld,
135 SanitizeThreadRequiresLibCpp,137 SanitizeThreadRequiresLibCpp,
136 LibCRequiresLibUnwind,138 LibCRequiresLibUnwind,
...@@ -142,6 +144,7 @@ pub const ResolveError = error{...@@ -142,6 +144,7 @@ pub const ResolveError = error{
142 TargetCannotStaticLinkExecutables,144 TargetCannotStaticLinkExecutables,
143 LibCRequiresDynamicLinking,145 LibCRequiresDynamicLinking,
144 SharedLibrariesRequireDynamicLinking,146 SharedLibrariesRequireDynamicLinking,
147 DynamicLinkingWithLldRequiresSharedLibraries,
145 ExportMemoryAndDynamicIncompatible,148 ExportMemoryAndDynamicIncompatible,
146 DynamicLibraryPrecludesPie,149 DynamicLibraryPrecludesPie,
147 TargetRequiresPie,150 TargetRequiresPie,
...@@ -274,16 +277,11 @@ pub fn resolve(options: Options) ResolveError!Config {...@@ -274,16 +277,11 @@ pub fn resolve(options: Options) ResolveError!Config {
274 if (options.link_mode == .static) return error.LibCRequiresDynamicLinking;277 if (options.link_mode == .static) return error.LibCRequiresDynamicLinking;
275 break :b .dynamic;278 break :b .dynamic;
276 }279 }
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
285 if (options.link_mode) |link_mode| break :b link_mode;281 if (options.link_mode) |link_mode| break :b link_mode;
286282
283 if (options.any_dyn_libs) break :b .dynamic;
284
287 if (explicitly_exe_or_dyn_lib and link_libc) {285 if (explicitly_exe_or_dyn_lib and link_libc) {
288 // When using the native glibc/musl ABI, dynamic linking is usually what people want.286 // When using the native glibc/musl ABI, dynamic linking is usually what people want.
289 if (options.resolved_target.is_native_abi and (target.isGnuLibC() or target.isMuslLibC())) {287 if (options.resolved_target.is_native_abi and (target.isGnuLibC() or target.isMuslLibC())) {
...@@ -425,6 +423,25 @@ pub fn resolve(options: Options) ResolveError!Config {...@@ -425,6 +423,25 @@ pub fn resolve(options: Options) ResolveError!Config {
425 break :b use_llvm;423 break :b use_llvm;
426 };424 };
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
428 const use_new_linker = b: {445 const use_new_linker = b: {
429 if (use_lld) {446 if (use_lld) {
430 if (options.use_new_linker == true) return error.NewLinkerIncompatibleWithLld;447 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 {...@@ -182,6 +182,10 @@ pub fn emitMir(emit: *Emit) Error!void {
182 try elf_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null)182 try elf_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null)
183 else if (emit.bin_file.cast(.elf2)) |elf| @intFromEnum(try elf.globalSymbol(.{183 else if (emit.bin_file.cast(.elf2)) |elf| @intFromEnum(try elf.globalSymbol(.{
184 .name = extern_func.toSlice(&emit.lower.mir).?,184 .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 },
185 .type = .FUNC,189 .type = .FUNC,
186 })) else if (emit.bin_file.cast(.macho)) |macho_file|190 })) else if (emit.bin_file.cast(.macho)) |macho_file|
187 try macho_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null)191 try macho_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null)
...@@ -320,10 +324,12 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -320,10 +324,12 @@ pub fn emitMir(emit: *Emit) Error!void {
320 }, emit.lower.target), &.{.{324 }, emit.lower.target), &.{.{
321 .op_index = 0,325 .op_index = 0,
322 .target = .{326 .target = .{
323 .index = if (emit.bin_file.cast(.elf)) |elf_file|327 .index = if (emit.bin_file.cast(.elf)) |elf_file| try elf_file.getGlobalSymbol(
324 try elf_file.getGlobalSymbol("__tls_get_addr", null)328 "__tls_get_addr",
325 else if (emit.bin_file.cast(.elf2)) |elf| @intFromEnum(try elf.globalSymbol(.{329 if (comp.config.link_libc) "c" else null,
330 ) else if (emit.bin_file.cast(.elf2)) |elf| @intFromEnum(try elf.globalSymbol(.{
326 .name = "__tls_get_addr",331 .name = "__tls_get_addr",
332 .lib_name = if (comp.config.link_libc) "c" else null,
327 .type = .FUNC,333 .type = .FUNC,
328 })) else unreachable,334 })) else unreachable,
329 .is_extern = true,335 .is_extern = true,
src/link/Elf.zig+11-7
...@@ -1882,17 +1882,13 @@ fn initSyntheticSections(self: *Elf) !void {...@@ -1882,17 +1882,13 @@ fn initSyntheticSections(self: *Elf) !void {
1882 const comp = self.base.comp;1882 const comp = self.base.comp;
1883 const target = self.getTarget();1883 const target = self.getTarget();
1884 const ptr_size = self.ptrWidthBytes();1884 const ptr_size = self.ptrWidthBytes();
1885 const shared_objects = self.shared_objects.values();
18861885
1887 const is_exe_or_dyn_lib = switch (comp.config.output_mode) {1886 const is_exe_or_dyn_lib = switch (comp.config.output_mode) {
1888 .Exe => true,1887 .Exe => true,
1889 .Lib => comp.config.link_mode == .dynamic,1888 .Lib => comp.config.link_mode == .dynamic,
1890 .Obj => false,1889 .Obj => false,
1891 };1890 };
1892 const have_dynamic_linker = comp.config.link_mode == .dynamic and is_exe_or_dyn_lib and !target.dynamic_linker.eql(.none);1891 const have_dynamic_linker = comp.config.link_mode == .dynamic and is_exe_or_dyn_lib;
1893
1894 const needs_interp = have_dynamic_linker and
1895 (comp.config.link_libc or comp.root_mod.resolved_target.is_explicit_dynamic_linker);
18961892
1897 const needs_eh_frame = blk: {1893 const needs_eh_frame = blk: {
1898 if (self.zigObjectPtr()) |zo|1894 if (self.zigObjectPtr()) |zo|
...@@ -2004,7 +2000,15 @@ fn initSyntheticSections(self: *Elf) !void {...@@ -2004,7 +2000,15 @@ fn initSyntheticSections(self: *Elf) !void {
2004 });2000 });
2005 }2001 }
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) {
2008 self.section_indexes.interp = try self.addSection(.{2012 self.section_indexes.interp = try self.addSection(.{
2009 .name = try self.insertShString(".interp"),2013 .name = try self.insertShString(".interp"),
2010 .type = elf.SHT_PROGBITS,2014 .type = elf.SHT_PROGBITS,
...@@ -2013,7 +2017,7 @@ fn initSyntheticSections(self: *Elf) !void {...@@ -2013,7 +2017,7 @@ fn initSyntheticSections(self: *Elf) !void {
2013 });2017 });
2014 }2018 }
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()) {
2017 if (self.section_indexes.dynstrtab == null) {2021 if (self.section_indexes.dynstrtab == null) {
2018 self.section_indexes.dynstrtab = try self.addSection(.{2022 self.section_indexes.dynstrtab = try self.addSection(.{
2019 .name = try self.insertShString(".dynstr"),2023 .name = try self.insertShString(".dynstr"),
src/link/Elf2.zig+527-178
...@@ -1,11 +1,16 @@...@@ -1,11 +1,16 @@
1base: link.File,1base: link.File,
2options: link.File.OpenOptions,
2mf: MappedFile,3mf: MappedFile,
3known: Node.Known,4ni: Node.Known,
4nodes: std.MultiArrayList(Node),5nodes: std.MultiArrayList(Node),
5phdrs: std.ArrayList(MappedFile.Node.Index),6phdrs: std.ArrayList(MappedFile.Node.Index),
7si: Symbol.Known,
6symtab: std.ArrayList(Symbol),8symtab: std.ArrayList(Symbol),
7shstrtab: StringTable,9shstrtab: StringTable,
8strtab: StringTable,10strtab: StringTable,
11dynsym: std.ArrayList(Symbol.Index),
12dynstr: StringTable,
13needed: std.AutoArrayHashMapUnmanaged(u32, void),
9inputs: std.ArrayList(struct {14inputs: std.ArrayList(struct {
10 path: std.Build.Cache.Path,15 path: std.Build.Cache.Path,
11 member: ?[]const u8,16 member: ?[]const u8,
...@@ -143,13 +148,13 @@ pub const Node = union(enum) {...@@ -143,13 +148,13 @@ pub const Node = union(enum) {
143 };148 };
144149
145 pub const Known = struct {150 pub const Known = struct {
146 pub const rodata: MappedFile.Node.Index = @enumFromInt(1);151 comptime file: MappedFile.Node.Index = .root,
147 pub const ehdr: MappedFile.Node.Index = @enumFromInt(2);152 comptime ehdr: MappedFile.Node.Index = @enumFromInt(1),
148 pub const phdr: MappedFile.Node.Index = @enumFromInt(3);153 comptime shdr: MappedFile.Node.Index = @enumFromInt(2),
149 pub const shdr: MappedFile.Node.Index = @enumFromInt(4);154 comptime rodata: MappedFile.Node.Index = @enumFromInt(3),
150 pub const text: MappedFile.Node.Index = @enumFromInt(5);155 comptime phdr: MappedFile.Node.Index = @enumFromInt(4),
151 pub const data: MappedFile.Node.Index = @enumFromInt(6);156 comptime text: MappedFile.Node.Index = @enumFromInt(5),
152157 comptime data: MappedFile.Node.Index = @enumFromInt(6),
153 tls: MappedFile.Node.Index,158 tls: MappedFile.Node.Index,
154 };159 };
155160
...@@ -231,7 +236,6 @@ pub const Symbol = struct {...@@ -231,7 +236,6 @@ pub const Symbol = struct {
231 rodata,236 rodata,
232 text,237 text,
233 data,238 data,
234 tdata,
235 _,239 _,
236240
237 pub fn get(si: Symbol.Index, elf: *Elf) *Symbol {241 pub fn get(si: Symbol.Index, elf: *Elf) *Symbol {
...@@ -250,6 +254,7 @@ pub const Symbol = struct {...@@ -250,6 +254,7 @@ pub const Symbol = struct {
250254
251 pub const InitOptions = struct {255 pub const InitOptions = struct {
252 name: []const u8 = "",256 name: []const u8 = "",
257 lib_name: ?[]const u8 = null,
253 value: u64 = 0,258 value: u64 = 0,
254 size: u64 = 0,259 size: u64 = 0,
255 type: std.elf.STT,260 type: std.elf.STT,
...@@ -258,29 +263,45 @@ pub const Symbol = struct {...@@ -258,29 +263,45 @@ pub const Symbol = struct {
258 shndx: std.elf.Section = std.elf.SHN_UNDEF,263 shndx: std.elf.Section = std.elf.SHN_UNDEF,
259 };264 };
260 pub fn init(si: Symbol.Index, elf: *Elf, opts: InitOptions) !void {265 pub fn init(si: Symbol.Index, elf: *Elf, opts: InitOptions) !void {
261 const name_entry = try elf.string(.strtab, opts.name);266 const gpa = elf.base.comp.gpa;
262 try Symbol.Index.symtab.node(elf).resize(267 const target_endian = elf.targetEndian();
263 &elf.mf,268 const sym_size: usize = switch (elf.identClass()) {
264 elf.base.comp.gpa,269 .NONE, _ => unreachable,
265 @as(usize, switch (elf.identClass()) {270 inline else => |class| @sizeOf(class.ElfN().Sym),
266 .NONE, _ => unreachable,271 };
267 .@"32" => @sizeOf(std.elf.Elf32.Sym),272 const name_strtab_entry = try elf.string(.strtab, opts.name);
268 .@"64" => @sizeOf(std.elf.Elf64.Sym),273 try elf.si.symtab.node(elf).resize(&elf.mf, gpa, sym_size * elf.symtab.items.len);
269 }) * elf.symtab.items.len,
270 );
271 switch (elf.symPtr(si)) {274 switch (elf.symPtr(si)) {
272 inline else => |sym| sym.* = .{275 inline else => |sym, class| {
273 .name = name_entry,276 sym.* = .{
274 .value = @intCast(opts.value),277 .name = name_strtab_entry,
275 .size = @intCast(opts.size),278 .value = @intCast(opts.value),
276 .info = .{279 .size = @intCast(opts.size),
277 .type = opts.type,280 .info = .{ .type = opts.type, .bind = opts.bind },
278 .bind = opts.bind,281 .other = .{ .visibility = opts.visibility },
279 },282 .shndx = opts.shndx,
280 .other = .{283 };
281 .visibility = opts.visibility,284 if (target_endian != native_endian) std.mem.byteSwapAllFields(class.ElfN().Sym, sym);
282 },285 },
283 .shndx = opts.shndx,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);
284 },305 },
285 }306 }
286 }307 }
...@@ -329,6 +350,19 @@ pub const Symbol = struct {...@@ -329,6 +350,19 @@ pub const Symbol = struct {
329 }350 }
330 };351 };
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
332 comptime {366 comptime {
333 if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Symbol) == 16);367 if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Symbol) == 16);
334 }368 }
...@@ -349,6 +383,22 @@ pub const Reloc = extern struct {...@@ -349,6 +383,22 @@ pub const Reloc = extern struct {
349 AARCH64: std.elf.R_AARCH64,383 AARCH64: std.elf.R_AARCH64,
350 RISCV: std.elf.R_RISCV,384 RISCV: std.elf.R_RISCV,
351 PPC64: std.elf.R_PPC64,385 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 }
352 };402 };
353403
354 pub const Index = enum(u32) {404 pub const Index = enum(u32) {
...@@ -411,7 +461,7 @@ pub const Reloc = extern struct {...@@ -411,7 +461,7 @@ pub const Reloc = extern struct {
411 ),461 ),
412 .TPOFF32 => {462 .TPOFF32 => {
413 const phdr = @field(elf.phdrSlice(), @tagName(class));463 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];
415 assert(elf.targetLoad(&ph.type) == std.elf.PT_TLS);465 assert(elf.targetLoad(&ph.type) == std.elf.PT_TLS);
416 std.mem.writeInt(466 std.mem.writeInt(
417 i32,467 i32,
...@@ -420,6 +470,18 @@ pub const Reloc = extern struct {...@@ -420,6 +470,18 @@ pub const Reloc = extern struct {
420 target_endian,470 target_endian,
421 );471 );
422 },472 },
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 ),
423 },485 },
424 }486 }
425 },487 },
...@@ -469,7 +531,6 @@ fn create(...@@ -469,7 +531,6 @@ fn create(
469 path: std.Build.Cache.Path,531 path: std.Build.Cache.Path,
470 options: link.File.OpenOptions,532 options: link.File.OpenOptions,
471) !*Elf {533) !*Elf {
472 _ = options;
473 const target = &comp.root_mod.resolved_target.result;534 const target = &comp.root_mod.resolved_target.result;
474 assert(target.ofmt == .elf);535 assert(target.ofmt == .elf);
475 const class: std.elf.CLASS = switch (target.ptrBitWidth()) {536 const class: std.elf.CLASS = switch (target.ptrBitWidth()) {
...@@ -502,12 +563,16 @@ fn create(...@@ -502,12 +563,16 @@ fn create(
502 .Obj => .REL,563 .Obj => .REL,
503 };564 };
504 const machine = target.toElfMachine();565 const machine = target.toElfMachine();
505 const maybe_interp = switch (comp.config.output_mode) {566 const maybe_interp = switch (comp.config.link_mode) {
506 .Exe, .Lib => switch (comp.config.link_mode) {567 .static => null,
507 .static => null,568 .dynamic => switch (comp.config.output_mode) {
508 .dynamic => target.dynamic_linker.get(),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,
509 },575 },
510 .Obj => null,
511 };576 };
512577
513 const elf = try arena.create(Elf);578 const elf = try arena.create(Elf);
...@@ -530,12 +595,19 @@ fn create(...@@ -530,12 +595,19 @@ fn create(
530 .allow_shlib_undefined = false,595 .allow_shlib_undefined = false,
531 .stack_size = 0,596 .stack_size = 0,
532 },597 },
598 .options = options,
533 .mf = try .init(file, comp.gpa),599 .mf = try .init(file, comp.gpa),
534 .known = .{600 .ni = .{
535 .tls = .none,601 .tls = .none,
536 },602 },
537 .nodes = .empty,603 .nodes = .empty,
538 .phdrs = .empty,604 .phdrs = .empty,
605 .si = .{
606 .dynsym = .null,
607 .dynstr = .null,
608 .dynamic = .null,
609 .tdata = .null,
610 },
539 .symtab = .empty,611 .symtab = .empty,
540 .shstrtab = .{612 .shstrtab = .{
541 .map = .empty,613 .map = .empty,
...@@ -545,6 +617,12 @@ fn create(...@@ -545,6 +617,12 @@ fn create(
545 .map = .empty,617 .map = .empty,
546 .size = 1,618 .size = 1,
547 },619 },
620 .dynsym = .empty,
621 .dynstr = .{
622 .map = .empty,
623 .size = 1,
624 },
625 .needed = .empty,
548 .inputs = .empty,626 .inputs = .empty,
549 .input_sections = .empty,627 .input_sections = .empty,
550 .input_section_pending_index = 0,628 .input_section_pending_index = 0,
...@@ -576,6 +654,9 @@ pub fn deinit(elf: *Elf) void {...@@ -576,6 +654,9 @@ pub fn deinit(elf: *Elf) void {
576 elf.symtab.deinit(gpa);654 elf.symtab.deinit(gpa);
577 elf.shstrtab.map.deinit(gpa);655 elf.shstrtab.map.deinit(gpa);
578 elf.strtab.map.deinit(gpa);656 elf.strtab.map.deinit(gpa);
657 elf.dynsym.deinit(gpa);
658 elf.dynstr.map.deinit(gpa);
659 elf.needed.deinit(gpa);
579 for (elf.inputs.items) |input| if (input.member) |m| gpa.free(m);660 for (elf.inputs.items) |input| if (input.member) |m| gpa.free(m);
580 elf.inputs.deinit(gpa);661 elf.inputs.deinit(gpa);
581 elf.input_sections.deinit(gpa);662 elf.input_sections.deinit(gpa);
...@@ -599,6 +680,13 @@ fn initHeaders(...@@ -599,6 +680,13 @@ fn initHeaders(
599) !void {680) !void {
600 const comp = elf.base.comp;681 const comp = elf.base.comp;
601 const gpa = comp.gpa;682 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 };
602 const addr_align: std.mem.Alignment = switch (class) {690 const addr_align: std.mem.Alignment = switch (class) {
603 .NONE, _ => unreachable,691 .NONE, _ => unreachable,
604 .@"32" => .@"4",692 .@"32" => .@"4",
...@@ -618,37 +706,32 @@ fn initHeaders(...@@ -618,37 +706,32 @@ fn initHeaders(
618 phnum += 1;706 phnum += 1;
619 const data_phndx = phnum;707 const data_phndx = phnum;
620 phnum += 1;708 phnum += 1;
709 const dynamic_phndx = if (have_dynamic_section) phndx: {
710 defer phnum += 1;
711 break :phndx phnum;
712 } else undefined;
621 const tls_phndx = if (comp.config.any_non_single_threaded) phndx: {713 const tls_phndx = if (comp.config.any_non_single_threaded) phndx: {
622 defer phnum += 1;714 defer phnum += 1;
623 break :phndx phnum;715 break :phndx phnum;
624 } else undefined;716 } 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);
627 try elf.nodes.ensureTotalCapacity(gpa, expected_nodes_len);719 try elf.nodes.ensureTotalCapacity(gpa, expected_nodes_len);
628 try elf.phdrs.resize(gpa, phnum);720 try elf.phdrs.resize(gpa, phnum);
629 elf.nodes.appendAssumeCapacity(.file);721 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
640 switch (class) {723 switch (class) {
641 .NONE, _ => unreachable,724 .NONE, _ => unreachable,
642 inline else => |ct_class| {725 inline else => |ct_class| {
643 const ElfN = ct_class.ElfN();726 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, .{
645 .size = @sizeOf(ElfN.Ehdr),728 .size = @sizeOf(ElfN.Ehdr),
646 .alignment = addr_align,729 .alignment = addr_align,
647 .fixed = true,730 .fixed = true,
648 }));731 }));
649 elf.nodes.appendAssumeCapacity(.ehdr);732 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)));
652 const EI = std.elf.EI;735 const EI = std.elf.EI;
653 @memcpy(ehdr.ident[0..std.elf.MAGIC.len], std.elf.MAGIC);736 @memcpy(ehdr.ident[0..std.elf.MAGIC.len], std.elf.MAGIC);
654 ehdr.ident[EI.CLASS] = @intFromEnum(class);737 ehdr.ident[EI.CLASS] = @intFromEnum(class);
...@@ -674,37 +757,47 @@ fn initHeaders(...@@ -674,37 +757,47 @@ fn initHeaders(
674 },757 },
675 }758 }
676759
677 assert(Node.Known.phdr == try elf.mf.addLastChildNode(gpa, Node.Known.rodata, .{760 assert(elf.ni.shdr == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{
678 .size = elf.ehdrField(.phentsize) * elf.ehdrField(.phnum),761 .size = elf.ehdrField(.shentsize) * elf.ehdrField(.shnum),
679 .alignment = addr_align,762 .alignment = addr_align,
680 .moved = true,763 .moved = true,
681 .resized = true,764 .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,
682 .bubbles_moved = false,771 .bubbles_moved = false,
683 }));772 }));
684 elf.nodes.appendAssumeCapacity(.{ .segment = phdr_phndx });773 elf.nodes.appendAssumeCapacity(.{ .segment = rodata_phndx });
685 elf.phdrs.items[phdr_phndx] = Node.Known.phdr;774 elf.phdrs.items[rodata_phndx] = elf.ni.rodata;
686775
687 assert(Node.Known.shdr == try elf.mf.addLastChildNode(gpa, Node.Known.rodata, .{776 assert(elf.ni.phdr == try elf.mf.addOnlyChildNode(gpa, elf.ni.rodata, .{
688 .size = elf.ehdrField(.shentsize) * elf.ehdrField(.shnum),777 .size = elf.ehdrField(.phentsize) * elf.ehdrField(.phnum),
689 .alignment = addr_align,778 .alignment = addr_align,
779 .moved = true,
780 .resized = true,
781 .bubbles_moved = false,
690 }));782 }));
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, .{
694 .alignment = elf.mf.flags.block_size,787 .alignment = elf.mf.flags.block_size,
695 .moved = true,788 .moved = true,
696 .bubbles_moved = false,789 .bubbles_moved = false,
697 }));790 }));
698 elf.nodes.appendAssumeCapacity(.{ .segment = text_phndx });791 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, .{
702 .alignment = elf.mf.flags.block_size,795 .alignment = elf.mf.flags.block_size,
703 .moved = true,796 .moved = true,
704 .bubbles_moved = false,797 .bubbles_moved = false,
705 }));798 }));
706 elf.nodes.appendAssumeCapacity(.{ .segment = data_phndx });799 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
709 var ph_vaddr: u32 = switch (elf.ehdrField(.type)) {802 var ph_vaddr: u32 = switch (elf.ehdrField(.type)) {
710 else => 0,803 else => 0,
...@@ -723,7 +816,7 @@ fn initHeaders(...@@ -723,7 +816,7 @@ fn initHeaders(
723 const ElfN = ct_class.ElfN();816 const ElfN = ct_class.ElfN();
724 const target_endian = elf.targetEndian();817 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)));
727 const ph_phdr = &phdr[phdr_phndx];820 const ph_phdr = &phdr[phdr_phndx];
728 ph_phdr.* = .{821 ph_phdr.* = .{
729 .type = std.elf.PT_PHDR,822 .type = std.elf.PT_PHDR,
...@@ -733,7 +826,7 @@ fn initHeaders(...@@ -733,7 +826,7 @@ fn initHeaders(
733 .filesz = 0,826 .filesz = 0,
734 .memsz = 0,827 .memsz = 0,
735 .flags = .{ .R = true },828 .flags = .{ .R = true },
736 .@"align" = @intCast(Node.Known.phdr.alignment(&elf.mf).toByteUnits()),829 .@"align" = @intCast(elf.ni.phdr.alignment(&elf.mf).toByteUnits()),
737 };830 };
738 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_phdr);831 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_phdr);
739832
...@@ -752,7 +845,7 @@ fn initHeaders(...@@ -752,7 +845,7 @@ fn initHeaders(
752 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_interp);845 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_interp);
753 }846 }
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);
756 const ph_rodata = &phdr[rodata_phndx];849 const ph_rodata = &phdr[rodata_phndx];
757 ph_rodata.* = .{850 ph_rodata.* = .{
758 .type = std.elf.PT_NULL,851 .type = std.elf.PT_NULL,
...@@ -762,12 +855,12 @@ fn initHeaders(...@@ -762,12 +855,12 @@ fn initHeaders(
762 .filesz = @intCast(rodata_size),855 .filesz = @intCast(rodata_size),
763 .memsz = @intCast(rodata_size),856 .memsz = @intCast(rodata_size),
764 .flags = .{ .R = true },857 .flags = .{ .R = true },
765 .@"align" = @intCast(Node.Known.rodata.alignment(&elf.mf).toByteUnits()),858 .@"align" = @intCast(elf.ni.rodata.alignment(&elf.mf).toByteUnits()),
766 };859 };
767 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_rodata);860 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_rodata);
768 ph_vaddr += @intCast(rodata_size);861 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);
771 const ph_text = &phdr[text_phndx];864 const ph_text = &phdr[text_phndx];
772 ph_text.* = .{865 ph_text.* = .{
773 .type = std.elf.PT_NULL,866 .type = std.elf.PT_NULL,
...@@ -777,12 +870,12 @@ fn initHeaders(...@@ -777,12 +870,12 @@ fn initHeaders(
777 .filesz = @intCast(text_size),870 .filesz = @intCast(text_size),
778 .memsz = @intCast(text_size),871 .memsz = @intCast(text_size),
779 .flags = .{ .R = true, .X = true },872 .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()),
781 };874 };
782 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_text);875 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_text);
783 ph_vaddr += @intCast(text_size);876 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);
786 const ph_data = &phdr[data_phndx];879 const ph_data = &phdr[data_phndx];
787 ph_data.* = .{880 ph_data.* = .{
788 .type = std.elf.PT_NULL,881 .type = std.elf.PT_NULL,
...@@ -792,11 +885,26 @@ fn initHeaders(...@@ -792,11 +885,26 @@ fn initHeaders(
792 .filesz = @intCast(data_size),885 .filesz = @intCast(data_size),
793 .memsz = @intCast(data_size),886 .memsz = @intCast(data_size),
794 .flags = .{ .R = true, .W = true },887 .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()),
796 };889 };
797 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_data);890 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_data);
798 ph_vaddr += @intCast(data_size);891 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
800 if (comp.config.any_non_single_threaded) {908 if (comp.config.any_non_single_threaded) {
801 const ph_tls = &phdr[tls_phndx];909 const ph_tls = &phdr[tls_phndx];
802 ph_tls.* = .{910 ph_tls.* = .{
...@@ -812,7 +920,7 @@ fn initHeaders(...@@ -812,7 +920,7 @@ fn initHeaders(
812 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_tls);920 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_tls);
813 }921 }
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)));
816 sh_null.* = .{924 sh_null.* = .{
817 .name = try elf.string(.shstrtab, ""),925 .name = try elf.string(.shstrtab, ""),
818 .type = std.elf.SHT_NULL,926 .type = std.elf.SHT_NULL,
...@@ -834,99 +942,142 @@ fn initHeaders(...@@ -834,99 +942,142 @@ fn initHeaders(
834 .target_relocs = .none,942 .target_relocs = .none,
835 .unused = 0,943 .unused = 0,
836 };944 };
837 assert(try elf.addSection(Node.Known.rodata, .{945 assert(elf.si.symtab == try elf.addSection(elf.ni.file, .{
838 .type = std.elf.SHT_SYMTAB,946 .type = std.elf.SHT_SYMTAB,
947 .size = @sizeOf(ElfN.Sym) * 1,
839 .addralign = addr_align,948 .addralign = addr_align,
840 .entsize = @sizeOf(ElfN.Sym),949 .entsize = @sizeOf(ElfN.Sym),
841 }) == .symtab);950 }));
842951 const symtab_null = @field(elf.symPtr(.null), @tagName(ct_class));
843 const symtab: *ElfN.Sym = @ptrCast(@alignCast(Symbol.Index.symtab.node(elf).slice(&elf.mf)));952 symtab_null.* = .{
844 symtab.* = .{
845 .name = try elf.string(.strtab, ""),953 .name = try elf.string(.strtab, ""),
846 .value = 0,954 .value = 0,
847 .size = 0,955 .size = 0,
848 .info = .{956 .info = .{ .type = .NOTYPE, .bind = .LOCAL },
849 .type = .NOTYPE,957 .other = .{ .visibility = .DEFAULT },
850 .bind = .LOCAL,
851 },
852 .other = .{
853 .visibility = .DEFAULT,
854 },
855 .shndx = std.elf.SHN_UNDEF,958 .shndx = std.elf.SHN_UNDEF,
856 };959 };
960 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Sym, symtab_null);
857961
858 const ehdr = @field(elf.ehdrPtr(), @tagName(ct_class));962 const ehdr = @field(elf.ehdrPtr(), @tagName(ct_class));
859 ehdr.shstrndx = ehdr.shnum;963 ehdr.shstrndx = ehdr.shnum;
860 },964 },
861 }965 }
862 assert(try elf.addSection(Node.Known.rodata, .{966 assert(elf.si.shstrtab == try elf.addSection(elf.ni.file, .{
863 .type = std.elf.SHT_STRTAB,967 .type = std.elf.SHT_STRTAB,
864 .addralign = elf.mf.flags.block_size,968 .addralign = elf.mf.flags.block_size,
865 .entsize = 1,969 .entsize = 1,
866 }) == .shstrtab);970 }));
867 try elf.renameSection(.symtab, ".symtab");971 try elf.renameSection(.symtab, ".symtab");
868 try elf.renameSection(.shstrtab, ".shstrtab");972 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, .{
872 .name = ".strtab",976 .name = ".strtab",
873 .type = std.elf.SHT_STRTAB,977 .type = std.elf.SHT_STRTAB,
874 .addralign = elf.mf.flags.block_size,
875 .size = 1,978 .size = 1,
979 .addralign = elf.mf.flags.block_size,
876 .entsize = 1,980 .entsize = 1,
877 }) == .strtab);981 }));
878 try elf.linkSections(.symtab, .strtab);982 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, .{
882 .name = ".rodata",986 .name = ".rodata",
883 .flags = .{ .ALLOC = true },987 .flags = .{ .ALLOC = true },
884 .addralign = elf.mf.flags.block_size,988 .addralign = elf.mf.flags.block_size,
885 }) == .rodata);989 }));
886 assert(try elf.addSection(Node.Known.text, .{990 assert(elf.si.text == try elf.addSection(elf.ni.text, .{
887 .name = ".text",991 .name = ".text",
888 .flags = .{ .ALLOC = true, .EXECINSTR = true },992 .flags = .{ .ALLOC = true, .EXECINSTR = true },
889 .addralign = elf.mf.flags.block_size,993 .addralign = elf.mf.flags.block_size,
890 }) == .text);994 }));
891 assert(try elf.addSection(Node.Known.data, .{995 assert(elf.si.data == try elf.addSection(elf.ni.data, .{
892 .name = ".data",996 .name = ".data",
893 .flags = .{ .WRITE = true, .ALLOC = true },997 .flags = .{ .WRITE = true, .ALLOC = true },
894 .addralign = elf.mf.flags.block_size,998 .addralign = elf.mf.flags.block_size,
895 }) == .data);999 }));
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 }
911 if (maybe_interp) |interp| {1000 if (maybe_interp) |interp| {
912 try elf.nodes.ensureUnusedCapacity(gpa, 1);1001 const interp_ni = try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{
913 const interp_ni = try elf.mf.addLastChildNode(gpa, Node.Known.rodata, .{
914 .size = interp.len + 1,1002 .size = interp.len + 1,
915 .moved = true,1003 .moved = true,
916 .resized = true,1004 .resized = true,
1005 .bubbles_moved = false,
917 });1006 });
918 elf.nodes.appendAssumeCapacity(.{ .segment = interp_phndx });1007 elf.nodes.appendAssumeCapacity(.{ .segment = interp_phndx });
919 elf.phdrs.items[interp_phndx] = interp_ni;1008 elf.phdrs.items[interp_phndx] = interp_ni;
9201009
921 const sec_interp_si = try elf.addSection(interp_ni, .{1010 const sec_interp_si = try elf.addSection(interp_ni, .{
922 .name = ".interp",1011 .name = ".interp",
923 .size = @intCast(interp.len + 1),
924 .flags = .{ .ALLOC = true },1012 .flags = .{ .ALLOC = true },
1013 .size = @intCast(interp.len + 1),
925 });1014 });
926 const sec_interp = sec_interp_si.node(elf).slice(&elf.mf);1015 const sec_interp = sec_interp_si.node(elf).slice(&elf.mf);
927 @memcpy(sec_interp[0..interp.len], interp);1016 @memcpy(sec_interp[0..interp.len], interp);
928 sec_interp[interp.len] = 0;1017 sec_interp[interp.len] = 0;
929 }1018 }
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 }
930 assert(elf.nodes.len == expected_nodes_len);1081 assert(elf.nodes.len == expected_nodes_len);
931}1082}
9321083
...@@ -962,7 +1113,8 @@ fn getNode(elf: *const Elf, ni: MappedFile.Node.Index) Node {...@@ -962,7 +1113,8 @@ fn getNode(elf: *const Elf, ni: MappedFile.Node.Index) Node {
962fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {1113fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {
963 const parent_vaddr = parent_vaddr: {1114 const parent_vaddr = parent_vaddr: {
964 const parent_si = switch (elf.getNode(ni.parent(&elf.mf))) {1115 const parent_si = switch (elf.getNode(ni.parent(&elf.mf))) {
965 .file, .ehdr, .shdr => unreachable,1116 .file => return 0,
1117 .ehdr, .shdr => unreachable,
966 .segment => |phndx| break :parent_vaddr switch (elf.phdrSlice()) {1118 .segment => |phndx| break :parent_vaddr switch (elf.phdrSlice()) {
967 inline else => |ph| elf.targetLoad(&ph[phndx].vaddr),1119 inline else => |ph| elf.targetLoad(&ph[phndx].vaddr),
968 },1120 },
...@@ -970,7 +1122,7 @@ fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {...@@ -970,7 +1122,7 @@ fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {
970 .input_section => unreachable,1122 .input_section => unreachable,
971 inline .nav, .uav, .lazy_code, .lazy_const_data => |mi| mi.symbol(elf),1123 inline .nav, .uav, .lazy_code, .lazy_const_data => |mi| mi.symbol(elf),
972 };1124 };
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)) {
974 inline else => |sym| elf.targetLoad(&sym.value),1126 inline else => |sym| elf.targetLoad(&sym.value),
975 };1127 };
976 };1128 };
...@@ -1025,7 +1177,7 @@ pub const EhdrPtr = union(std.elf.CLASS) {...@@ -1025,7 +1177,7 @@ pub const EhdrPtr = union(std.elf.CLASS) {
1025 @"64": *std.elf.Elf64.Ehdr,1177 @"64": *std.elf.Elf64.Ehdr,
1026};1178};
1027pub fn ehdrPtr(elf: *Elf) EhdrPtr {1179pub fn ehdrPtr(elf: *Elf) EhdrPtr {
1028 const slice = Node.Known.ehdr.slice(&elf.mf);1180 const slice = elf.ni.ehdr.slice(&elf.mf);
1029 return switch (elf.identClass()) {1181 return switch (elf.identClass()) {
1030 .NONE, _ => unreachable,1182 .NONE, _ => unreachable,
1031 inline else => |class| @unionInit(1183 inline else => |class| @unionInit(
...@@ -1050,7 +1202,7 @@ pub const PhdrSlice = union(std.elf.CLASS) {...@@ -1050,7 +1202,7 @@ pub const PhdrSlice = union(std.elf.CLASS) {
1050 @"64": []std.elf.Elf64.Phdr,1202 @"64": []std.elf.Elf64.Phdr,
1051};1203};
1052pub fn phdrSlice(elf: *Elf) PhdrSlice {1204pub fn phdrSlice(elf: *Elf) PhdrSlice {
1053 const slice = Node.Known.phdr.slice(&elf.mf);1205 const slice = elf.ni.phdr.slice(&elf.mf);
1054 return switch (elf.identClass()) {1206 return switch (elf.identClass()) {
1055 .NONE, _ => unreachable,1207 .NONE, _ => unreachable,
1056 inline else => |class| @unionInit(1208 inline else => |class| @unionInit(
...@@ -1067,7 +1219,7 @@ pub const ShdrSlice = union(std.elf.CLASS) {...@@ -1067,7 +1219,7 @@ pub const ShdrSlice = union(std.elf.CLASS) {
1067 @"64": []std.elf.Elf64.Shdr,1219 @"64": []std.elf.Elf64.Shdr,
1068};1220};
1069pub fn shdrSlice(elf: *Elf) ShdrSlice {1221pub fn shdrSlice(elf: *Elf) ShdrSlice {
1070 const slice = Node.Known.shdr.slice(&elf.mf);1222 const slice = elf.ni.shdr.slice(&elf.mf);
1071 return switch (elf.identClass()) {1223 return switch (elf.identClass()) {
1072 .NONE, _ => unreachable,1224 .NONE, _ => unreachable,
1073 inline else => |class| @unionInit(1225 inline else => |class| @unionInit(
...@@ -1084,7 +1236,7 @@ pub const SymtabSlice = union(std.elf.CLASS) {...@@ -1084,7 +1236,7 @@ pub const SymtabSlice = union(std.elf.CLASS) {
1084 @"64": []std.elf.Elf64.Sym,1236 @"64": []std.elf.Elf64.Sym,
1085};1237};
1086pub fn symtabSlice(elf: *Elf) SymtabSlice {1238pub 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);
1088 return switch (elf.identClass()) {1240 return switch (elf.identClass()) {
1089 .NONE, _ => unreachable,1241 .NONE, _ => unreachable,
1090 inline else => |class| @unionInit(1242 inline else => |class| @unionInit(
...@@ -1106,6 +1258,18 @@ pub fn symPtr(elf: *Elf, si: Symbol.Index) SymPtr {...@@ -1106,6 +1258,18 @@ pub fn symPtr(elf: *Elf, si: Symbol.Index) SymPtr {
1106 };1258 };
1107}1259}
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
1109fn addSymbolAssumeCapacity(elf: *Elf) Symbol.Index {1273fn addSymbolAssumeCapacity(elf: *Elf) Symbol.Index {
1110 defer elf.symtab.addOneAssumeCapacity().* = .{1274 defer elf.symtab.addOneAssumeCapacity().* = .{
1111 .ni = .none,1275 .ni = .none,
...@@ -1124,6 +1288,7 @@ fn initSymbolAssumeCapacity(elf: *Elf, opts: Symbol.Index.InitOptions) !Symbol.I...@@ -1124,6 +1288,7 @@ fn initSymbolAssumeCapacity(elf: *Elf, opts: Symbol.Index.InitOptions) !Symbol.I
11241288
1125pub fn globalSymbol(elf: *Elf, opts: struct {1289pub fn globalSymbol(elf: *Elf, opts: struct {
1126 name: []const u8,1290 name: []const u8,
1291 lib_name: ?[]const u8 = null,
1127 type: std.elf.STT,1292 type: std.elf.STT,
1128 bind: std.elf.STB = .GLOBAL,1293 bind: std.elf.STB = .GLOBAL,
1129 visibility: std.elf.STV = .DEFAULT,1294 visibility: std.elf.STV = .DEFAULT,
...@@ -1133,6 +1298,7 @@ pub fn globalSymbol(elf: *Elf, opts: struct {...@@ -1133,6 +1298,7 @@ pub fn globalSymbol(elf: *Elf, opts: struct {
1133 const global_gop = try elf.globals.getOrPut(gpa, try elf.string(.strtab, opts.name));1298 const global_gop = try elf.globals.getOrPut(gpa, try elf.string(.strtab, opts.name));
1134 if (!global_gop.found_existing) global_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{1299 if (!global_gop.found_existing) global_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{
1135 .name = opts.name,1300 .name = opts.name,
1301 .lib_name = opts.lib_name,
1136 .type = opts.type,1302 .type = opts.type,
1137 .bind = opts.bind,1303 .bind = opts.bind,
1138 .visibility = opts.visibility,1304 .visibility = opts.visibility,
...@@ -1169,15 +1335,15 @@ fn navType(...@@ -1169,15 +1335,15 @@ fn navType(
1169 },1335 },
1170 };1336 };
1171}1337}
1172fn namedSection(name: []const u8) ?Symbol.Index {1338fn namedSection(elf: *const Elf, name: []const u8) ?Symbol.Index {
1173 if (std.mem.eql(u8, name, ".rodata") or1339 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;
1175 if (std.mem.eql(u8, name, ".text") or1341 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;
1177 if (std.mem.eql(u8, name, ".data") or1343 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;
1179 if (std.mem.eql(u8, name, ".tdata") or1345 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;
1181 return null;1347 return null;
1182}1348}
1183fn navSection(1349fn navSection(
...@@ -1186,16 +1352,16 @@ fn navSection(...@@ -1186,16 +1352,16 @@ fn navSection(
1186 nav_fr: @FieldType(@FieldType(InternPool.Nav, "status"), "fully_resolved"),1352 nav_fr: @FieldType(@FieldType(InternPool.Nav, "status"), "fully_resolved"),
1187) Symbol.Index {1353) Symbol.Index {
1188 if (nav_fr.@"linksection".toSlice(ip)) |@"linksection"|1354 if (nav_fr.@"linksection".toSlice(ip)) |@"linksection"|
1189 if (namedSection(@"linksection")) |si| return si;1355 if (elf.namedSection(@"linksection")) |si| return si;
1190 return switch (navType(1356 return switch (navType(
1191 ip,1357 ip,
1192 .{ .fully_resolved = nav_fr },1358 .{ .fully_resolved = nav_fr },
1193 elf.base.comp.config.any_non_single_threaded,1359 elf.base.comp.config.any_non_single_threaded,
1194 )) {1360 )) {
1195 else => unreachable,1361 else => unreachable,
1196 .FUNC => .text,1362 .FUNC => elf.si.text,
1197 .OBJECT => .data,1363 .OBJECT => elf.si.data,
1198 .TLS => .tdata,1364 .TLS => elf.si.tdata,
1199 };1365 };
1200}1366}
1201fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Node.NavMapIndex {1367fn 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....@@ -1215,6 +1381,7 @@ pub fn navSymbol(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Symbol.
1215 const nav = ip.getNav(nav_index);1381 const nav = ip.getNav(nav_index);
1216 if (nav.getExtern(ip)) |@"extern"| return elf.globalSymbol(.{1382 if (nav.getExtern(ip)) |@"extern"| return elf.globalSymbol(.{
1217 .name = @"extern".name.toSlice(ip),1383 .name = @"extern".name.toSlice(ip),
1384 .lib_name = @"extern".lib_name.toSlice(ip),
1218 .type = navType(ip, nav.status, elf.base.comp.config.any_non_single_threaded),1385 .type = navType(ip, nav.status, elf.base.comp.config.any_non_single_threaded),
1219 .bind = switch (@"extern".linkage) {1386 .bind = switch (@"extern".linkage) {
1220 .internal => .LOCAL,1387 .internal => .LOCAL,
...@@ -1266,7 +1433,6 @@ pub fn loadInput(elf: *Elf, input: link.Input) (std.fs.File.Reader.SizeError ||...@@ -1266,7 +1433,6 @@ pub fn loadInput(elf: *Elf, input: link.Input) (std.fs.File.Reader.SizeError ||
1266 const io = elf.base.comp.io;1433 const io = elf.base.comp.io;
1267 var buf: [4096]u8 = undefined;1434 var buf: [4096]u8 = undefined;
1268 switch (input) {1435 switch (input) {
1269 else => {},
1270 .object => |object| {1436 .object => |object| {
1271 var fr = object.file.reader(io, &buf);1437 var fr = object.file.reader(io, &buf);
1272 elf.loadObject(object.path, null, &fr, .{1438 elf.loadObject(object.path, null, &fr, .{
...@@ -1284,6 +1450,16 @@ pub fn loadInput(elf: *Elf, input: link.Input) (std.fs.File.Reader.SizeError ||...@@ -1284,6 +1450,16 @@ pub fn loadInput(elf: *Elf, input: link.Input) (std.fs.File.Reader.SizeError ||
1284 else => |e| return e,1450 else => |e| return e,
1285 };1451 };
1286 },1452 },
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),
1287 }1463 }
1288}1464}
1289fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fr: *std.Io.File.Reader) !void {1465fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fr: *std.Io.File.Reader) !void {
...@@ -1382,7 +1558,7 @@ fn loadObject(...@@ -1382,7 +1558,7 @@ fn loadObject(
1382 return diags.failParse(path, "bad machine", .{});1558 return diags.failParse(path, "bad machine", .{});
1383 if (ehdr.shoff == 0 or ehdr.shnum <= 1) return;1559 if (ehdr.shoff == 0 or ehdr.shnum <= 1) return;
1384 if (ehdr.shoff + ehdr.shentsize * ehdr.shnum > fl.size)1560 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", .{});
1386 if (ehdr.shentsize < @sizeOf(ElfN.Shdr))1562 if (ehdr.shentsize < @sizeOf(ElfN.Shdr))
1387 return diags.failParse(path, "unsupported shentsize", .{});1563 return diags.failParse(path, "unsupported shentsize", .{});
1388 const sections = try gpa.alloc(struct { shdr: ElfN.Shdr, si: Symbol.Index }, ehdr.shnum);1564 const sections = try gpa.alloc(struct { shdr: ElfN.Shdr, si: Symbol.Index }, ehdr.shnum);
...@@ -1397,7 +1573,7 @@ fn loadObject(...@@ -1397,7 +1573,7 @@ fn loadObject(
1397 switch (section.shdr.type) {1573 switch (section.shdr.type) {
1398 std.elf.SHT_NULL, std.elf.SHT_NOBITS => {},1574 std.elf.SHT_NULL, std.elf.SHT_NOBITS => {},
1399 else => if (section.shdr.offset + section.shdr.size > fl.size)1575 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", .{}),
1401 }1577 }
1402 }1578 }
1403 const shstrtab = shstrtab: {1579 const shstrtab = shstrtab: {
...@@ -1421,7 +1597,7 @@ fn loadObject(...@@ -1421,7 +1597,7 @@ fn loadObject(
1421 std.elf.SHT_PROGBITS, std.elf.SHT_NOBITS => {1597 std.elf.SHT_PROGBITS, std.elf.SHT_NOBITS => {
1422 if (section.shdr.name >= shstrtab.len) continue;1598 if (section.shdr.name >= shstrtab.len) continue;
1423 const name = std.mem.sliceTo(shstrtab[section.shdr.name..], 0);1599 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;
1425 const ni = try elf.mf.addLastChildNode(gpa, parent_si.node(elf), .{1601 const ni = try elf.mf.addLastChildNode(gpa, parent_si.node(elf), .{
1426 .size = section.shdr.size,1602 .size = section.shdr.size,
1427 .alignment = .fromByteUnits(std.math.ceilPowerOfTwoAssert(1603 .alignment = .fromByteUnits(std.math.ceilPowerOfTwoAssert(
...@@ -1598,6 +1774,84 @@ fn loadObject(...@@ -1598,6 +1774,84 @@ fn loadObject(
1598 },1774 },
1599 }1775 }
1600}1776}
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
1602pub fn prelink(elf: *Elf, prog_node: std.Progress.Node) !void {1856pub fn prelink(elf: *Elf, prog_node: std.Progress.Node) !void {
1603 _ = prog_node;1857 _ = prog_node;
...@@ -1624,6 +1878,66 @@ fn prelinkInner(elf: *Elf) !void {...@@ -1624,6 +1878,66 @@ fn prelinkInner(elf: *Elf) !void {
1624 .member = null,1878 .member = null,
1625 .si = si,1879 .si = si,
1626 };1880 };
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 };
1627}1941}
16281942
1629pub fn getNavVAddr(1943pub fn getNavVAddr(
...@@ -1649,13 +1963,7 @@ pub fn getVAddr(elf: *Elf, reloc_info: link.File.RelocInfo, target_si: Symbol.In...@@ -1649,13 +1963,7 @@ pub fn getVAddr(elf: *Elf, reloc_info: link.File.RelocInfo, target_si: Symbol.In
1649 reloc_info.offset,1963 reloc_info.offset,
1650 target_si,1964 target_si,
1651 reloc_info.addend,1965 reloc_info.addend,
1652 switch (elf.ehdrField(.machine)) {1966 .absAddr(elf),
1653 else => unreachable,
1654 .AARCH64 => .{ .AARCH64 = .ABS64 },
1655 .PPC64 => .{ .PPC64 = .ADDR64 },
1656 .RISCV => .{ .RISCV = .@"64" },
1657 .X86_64 => .{ .X86_64 = .@"64" },
1658 },
1659 );1967 );
1660 return switch (elf.symPtr(target_si)) {1968 return switch (elf.symPtr(target_si)) {
1661 inline else => |sym| elf.targetLoad(&sym.value),1969 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...@@ -1665,11 +1973,16 @@ pub fn getVAddr(elf: *Elf, reloc_info: link.File.RelocInfo, target_si: Symbol.In
1665fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {1973fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
1666 name: []const u8 = "",1974 name: []const u8 = "",
1667 type: std.elf.Word = std.elf.SHT_NULL,1975 type: std.elf.Word = std.elf.SHT_NULL,
1668 size: std.elf.Word = 0,
1669 flags: std.elf.SHF = .{},1976 flags: std.elf.SHF = .{},
1977 size: std.elf.Word = 0,
1670 addralign: std.mem.Alignment = .@"1",1978 addralign: std.mem.Alignment = .@"1",
1671 entsize: std.elf.Word = 0,1979 entsize: std.elf.Word = 0,
1672}) !Symbol.Index {1980}) !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 }
1673 const gpa = elf.base.comp.gpa;1986 const gpa = elf.base.comp.gpa;
1674 try elf.nodes.ensureUnusedCapacity(gpa, 1);1987 try elf.nodes.ensureUnusedCapacity(gpa, 1);
1675 try elf.symtab.ensureUnusedCapacity(gpa, 1);1988 try elf.symtab.ensureUnusedCapacity(gpa, 1);
...@@ -1683,16 +1996,23 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {...@@ -1683,16 +1996,23 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
1683 break :shndx .{ shndx, elf.targetLoad(&ehdr.shentsize) * shnum };1996 break :shndx .{ shndx, elf.targetLoad(&ehdr.shentsize) * shnum };
1684 },1997 },
1685 };1998 };
1686 try Node.Known.shdr.resize(&elf.mf, gpa, shdr_size);1999 try elf.ni.shdr.resize(&elf.mf, gpa, shdr_size);
1687 const ni = try elf.mf.addLastChildNode(gpa, segment_ni, .{2000 const ni = try elf.mf.addLastChildNode(gpa, segment_ni, .{
1688 .alignment = opts.addralign,2001 .alignment = opts.addralign,
1689 .size = opts.size,2002 .size = opts.size,
1690 .moved = true,2003 .resized = opts.size > 0,
1691 });2004 });
1692 const si = elf.addSymbolAssumeCapacity();2005 const si = elf.addSymbolAssumeCapacity();
1693 elf.nodes.appendAssumeCapacity(.{ .section = si });2006 elf.nodes.appendAssumeCapacity(.{ .section = si });
1694 si.get(elf).ni = ni;2007 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 });
1696 switch (elf.shdrSlice()) {2016 switch (elf.shdrSlice()) {
1697 inline else => |shdr| {2017 inline else => |shdr| {
1698 const sh = &shdr[shndx];2018 const sh = &shdr[shndx];
...@@ -1700,8 +2020,8 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {...@@ -1700,8 +2020,8 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
1700 .name = shstrtab_entry,2020 .name = shstrtab_entry,
1701 .type = opts.type,2021 .type = opts.type,
1702 .flags = .{ .shf = opts.flags },2022 .flags = .{ .shf = opts.flags },
1703 .addr = 0,2023 .addr = @intCast(addr),
1704 .offset = 0,2024 .offset = @intCast(offset),
1705 .size = opts.size,2025 .size = opts.size,
1706 .link = 0,2026 .link = 0,
1707 .info = 0,2027 .info = 0,
...@@ -1733,7 +2053,7 @@ fn linkSections(elf: *Elf, si: Symbol.Index, link_si: Symbol.Index) !void {...@@ -1733,7 +2053,7 @@ fn linkSections(elf: *Elf, si: Symbol.Index, link_si: Symbol.Index) !void {
1733}2053}
17342054
1735fn sectionName(elf: *Elf, si: Symbol.Index) [:0]const u8 {2055fn 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()) {
1737 inline else => |shndx, class| elf.targetLoad(2057 inline else => |shndx, class| elf.targetLoad(
1738 &shndx[elf.targetLoad(&@field(elf.symPtr(si), @tagName(class)).shndx)].name,2058 &shndx[elf.targetLoad(&@field(elf.symPtr(si), @tagName(class)).shndx)].name,
1739 ),2059 ),
...@@ -1741,12 +2061,12 @@ fn sectionName(elf: *Elf, si: Symbol.Index) [:0]const u8 {...@@ -1741,12 +2061,12 @@ fn sectionName(elf: *Elf, si: Symbol.Index) [:0]const u8 {
1741 return name[0..std.mem.indexOfScalar(u8, name, 0).? :0];2061 return name[0..std.mem.indexOfScalar(u8, name, 0).? :0];
1742}2062}
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 {
1745 if (key.len == 0) return 0;2065 if (key.len == 0) return 0;
1746 return @field(elf, @tagName(section)).get(2066 return @field(elf, @tagName(section)).get(
1747 elf.base.comp.gpa,2067 elf.base.comp.gpa,
1748 &elf.mf,2068 &elf.mf,
1749 @field(Symbol.Index, @tagName(section)).node(elf),2069 @field(elf.si, @tagName(section)).node(elf),
1750 key,2070 key,
1751 );2071 );
1752}2072}
...@@ -2144,7 +2464,7 @@ fn flushUav(...@@ -2144,7 +2464,7 @@ fn flushUav(
2144 switch (sym.ni) {2464 switch (sym.ni) {
2145 .none => {2465 .none => {
2146 try elf.nodes.ensureUnusedCapacity(gpa, 1);2466 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), .{
2148 .alignment = uav_align.toStdMem(),2468 .alignment = uav_align.toStdMem(),
2149 .moved = true,2469 .moved = true,
2150 });2470 });
...@@ -2256,9 +2576,9 @@ fn flushInputSection(elf: *Elf, isi: Node.InputSectionIndex) !void {...@@ -2256,9 +2576,9 @@ fn flushInputSection(elf: *Elf, isi: Node.InputSectionIndex) !void {
2256 return error.EndOfStream;2576 return error.EndOfStream;
2257}2577}
22582578
2259fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {2579fn flushFileOffset(elf: *Elf, ni: MappedFile.Node.Index) !void {
2260 switch (elf.getNode(ni)) {2580 switch (elf.getNode(ni)) {
2261 .file => unreachable,2581 else => unreachable,
2262 .ehdr => assert(ni.fileLocation(&elf.mf, false).offset == 0),2582 .ehdr => assert(ni.fileLocation(&elf.mf, false).offset == 0),
2263 .shdr => switch (elf.ehdrPtr()) {2583 .shdr => switch (elf.ehdrPtr()) {
2264 inline else => |ehdr| elf.targetStore(2584 inline else => |ehdr| elf.targetStore(
...@@ -2266,32 +2586,61 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {...@@ -2266,32 +2586,61 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
2266 @intCast(ni.fileLocation(&elf.mf, false).offset),2586 @intCast(ni.fileLocation(&elf.mf, false).offset),
2267 ),2587 ),
2268 },2588 },
2269 .segment => |phndx| switch (elf.phdrSlice()) {2589 .segment => |phndx| {
2270 inline else => |phdr, class| {2590 switch (elf.phdrSlice()) {
2271 const ph = &phdr[phndx];2591 inline else => |phdr| elf.targetStore(
2272 elf.targetStore(&ph.offset, @intCast(ni.fileLocation(&elf.mf, false).offset));2592 &phdr[phndx].offset,
2273 switch (elf.targetLoad(&ph.type)) {2593 @intCast(ni.fileLocation(&elf.mf, false).offset),
2274 else => unreachable,2594 ),
2275 std.elf.PT_NULL, std.elf.PT_LOAD => return,2595 }
2276 std.elf.PT_DYNAMIC, std.elf.PT_INTERP => {},2596 var child_it = ni.children(&elf.mf);
2277 std.elf.PT_PHDR => @field(elf.ehdrPtr(), @tagName(class)).phoff = ph.offset,2597 while (child_it.next()) |child_ni| try elf.flushFileOffset(child_ni);
2278 std.elf.PT_TLS => {},
2279 }
2280 elf.targetStore(&ph.vaddr, @intCast(elf.computeNodeVAddr(ni)));
2281 ph.paddr = ph.vaddr;
2282 },
2283 },2598 },
2284 .section => |si| switch (elf.shdrSlice()) {2599 .section => |si| switch (elf.shdrSlice()) {
2285 inline else => |shdr, class| {2600 inline else => |shdr, class| elf.targetStore(
2286 const sym = @field(elf.symPtr(si), @tagName(class));2601 &shdr[elf.targetLoad(&@field(elf.symPtr(si), @tagName(class)).shndx)].offset,
2287 const sh = &shdr[elf.targetLoad(&sym.shndx)];2602 @intCast(ni.fileLocation(&elf.mf, false).offset),
2288 elf.targetStore(&sh.offset, @intCast(ni.fileLocation(&elf.mf, false).offset));2603 ),
2289 const flags = elf.targetLoad(&sh.flags).shf;2604 },
2290 if (flags.ALLOC) {2605 }
2291 elf.targetStore(&sh.addr, @intCast(elf.computeNodeVAddr(ni)));2606}
2292 if (!flags.TLS) sym.value = sh.addr;2607
2293 }2608fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
2294 },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);
2295 },2644 },
2296 .input_section => |isi| {2645 .input_section => |isi| {
2297 const old_addr = switch (elf.symPtr(isi.symbol(elf))) {2646 const old_addr = switch (elf.symPtr(isi.symbol(elf))) {
...@@ -2380,11 +2729,11 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {...@@ -2380,11 +2729,11 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {
2380 else => unreachable,2729 else => unreachable,
2381 std.elf.SHT_NULL => if (size > 0) elf.targetStore(&sh.type, std.elf.SHT_PROGBITS),2730 std.elf.SHT_NULL => if (size > 0) elf.targetStore(&sh.type, std.elf.SHT_PROGBITS),
2382 std.elf.SHT_PROGBITS => if (size == 0) elf.targetStore(&sh.type, std.elf.SHT_NULL),2731 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(
2384 &sh.info,2733 &sh.info,
2385 @intCast(@divExact(size, elf.targetLoad(&sh.entsize))),2734 @intCast(@divExact(size, elf.targetLoad(&sh.entsize))),
2386 ),2735 ),
2387 std.elf.SHT_STRTAB => {},2736 std.elf.SHT_STRTAB, std.elf.SHT_DYNAMIC => {},
2388 }2737 }
2389 },2738 },
2390 },2739 },
src/link/Lld.zig+4-5
...@@ -808,7 +808,6 @@ fn elfLink(lld: *Lld, arena: Allocator) !void {...@@ -808,7 +808,6 @@ fn elfLink(lld: *Lld, arena: Allocator) !void {
808 const link_mode = comp.config.link_mode;808 const link_mode = comp.config.link_mode;
809 const is_dyn_lib = link_mode == .dynamic and is_lib;809 const is_dyn_lib = link_mode == .dynamic and is_lib;
810 const is_exe_or_dyn_lib = is_dyn_lib or output_mode == .Exe;810 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;
812 const target = &comp.root_mod.resolved_target.result;811 const target = &comp.root_mod.resolved_target.result;
813 const compiler_rt_path: ?Cache.Path = blk: {812 const compiler_rt_path: ?Cache.Path = blk: {
814 if (comp.compiler_rt_lib) |x| break :blk x.full_object_path;813 if (comp.compiler_rt_lib) |x| break :blk x.full_object_path;
...@@ -1070,12 +1069,12 @@ fn elfLink(lld: *Lld, arena: Allocator) !void {...@@ -1070,12 +1069,12 @@ fn elfLink(lld: *Lld, arena: Allocator) !void {
1070 }1069 }
1071 }1070 }
10721071
1073 if (have_dynamic_linker and1072 if (output_mode == .Exe and link_mode == .dynamic) {
1074 (comp.config.link_libc or comp.root_mod.resolved_target.is_explicit_dynamic_linker))
1075 {
1076 if (target.dynamic_linker.get()) |dynamic_linker| {1073 if (target.dynamic_linker.get()) |dynamic_linker| {
1077 try argv.append("-dynamic-linker");1074 try argv.append("--dynamic-linker");
1078 try argv.append(dynamic_linker);1075 try argv.append(dynamic_linker);
1076 } else {
1077 try argv.append("--no-dynamic-linker");
1079 }1078 }
1080 }1079 }
10811080
src/main.zig+23-7
...@@ -558,6 +558,7 @@ const usage_build_generic =...@@ -558,6 +558,7 @@ const usage_build_generic =
558 \\ --enable-new-dtags Use the new behavior for dynamic tags (RUNPATH)558 \\ --enable-new-dtags Use the new behavior for dynamic tags (RUNPATH)
559 \\ --disable-new-dtags Use the old behavior for dynamic tags (RPATH)559 \\ --disable-new-dtags Use the old behavior for dynamic tags (RPATH)
560 \\ --dynamic-linker [path] Set the dynamic interpreter path (usually ld.so)560 \\ --dynamic-linker [path] Set the dynamic interpreter path (usually ld.so)
561 \\ --no-dynamic-linker Do not set any dynamic interpreter path
561 \\ --sysroot [path] Set the system root directory (usually /)562 \\ --sysroot [path] Set the system root directory (usually /)
562 \\ --version [ver] Dynamic library semver563 \\ --version [ver] Dynamic library semver
563 \\ -fentry Enable entry point with default symbol name564 \\ -fentry Enable entry point with default symbol name
...@@ -1301,6 +1302,8 @@ fn buildOutputType(...@@ -1301,6 +1302,8 @@ fn buildOutputType(
1301 mod_opts.optimize_mode = parseOptimizeMode(rest);1302 mod_opts.optimize_mode = parseOptimizeMode(rest);
1302 } else if (mem.eql(u8, arg, "--dynamic-linker")) {1303 } else if (mem.eql(u8, arg, "--dynamic-linker")) {
1303 create_module.dynamic_linker = args_iter.nextOrFatal();1304 create_module.dynamic_linker = args_iter.nextOrFatal();
1305 } else if (mem.eql(u8, arg, "--no-dynamic-linker")) {
1306 create_module.dynamic_linker = "";
1304 } else if (mem.eql(u8, arg, "--sysroot")) {1307 } else if (mem.eql(u8, arg, "--sysroot")) {
1305 const next_arg = args_iter.nextOrFatal();1308 const next_arg = args_iter.nextOrFatal();
1306 create_module.sysroot = next_arg;1309 create_module.sysroot = next_arg;
...@@ -2418,6 +2421,11 @@ fn buildOutputType(...@@ -2418,6 +2421,11 @@ fn buildOutputType(
2418 mem.eql(u8, arg, "-dynamic-linker"))2421 mem.eql(u8, arg, "-dynamic-linker"))
2419 {2422 {
2420 create_module.dynamic_linker = linker_args_it.nextOrFatal();2423 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 = "";
2421 } else if (mem.eql(u8, arg, "-E") or2429 } else if (mem.eql(u8, arg, "-E") or
2422 mem.eql(u8, arg, "--export-dynamic") or2430 mem.eql(u8, arg, "--export-dynamic") or
2423 mem.eql(u8, arg, "-export-dynamic"))2431 mem.eql(u8, arg, "-export-dynamic"))
...@@ -3191,13 +3199,14 @@ fn buildOutputType(...@@ -3191,13 +3199,14 @@ fn buildOutputType(
3191 const resolved_soname: ?[]const u8 = switch (soname) {3199 const resolved_soname: ?[]const u8 = switch (soname) {
3192 .yes => |explicit| explicit,3200 .yes => |explicit| explicit,
3193 .no => null,3201 .no => null,
3194 .yes_default_value => switch (target.ofmt) {3202 .yes_default_value => if (create_module.resolved_options.output_mode == .Lib and
3195 .elf => if (have_version)3203 create_module.resolved_options.link_mode == .dynamic and target.ofmt == .elf)
3204 if (have_version)
3196 try std.fmt.allocPrint(arena, "lib{s}.so.{d}", .{ root_name, version.major })3205 try std.fmt.allocPrint(arena, "lib{s}.so.{d}", .{ root_name, version.major })
3197 else3206 else
3198 try std.fmt.allocPrint(arena, "lib{s}.so", .{root_name}),3207 try std.fmt.allocPrint(arena, "lib{s}.so", .{root_name})
3199 else => null,3208 else
3200 },3209 null,
3201 };3210 };
32023211
3203 const emit_bin_resolved: Compilation.CreateOptions.Emit = switch (emit_bin) {3212 const emit_bin_resolved: Compilation.CreateOptions.Emit = switch (emit_bin) {
...@@ -3646,7 +3655,11 @@ fn buildOutputType(...@@ -3646,7 +3655,11 @@ fn buildOutputType(
3646 try test_exec_args.append(arena, try std.fmt.allocPrint(arena, "-mcpu={s}", .{mcpu}));3655 try test_exec_args.append(arena, try std.fmt.allocPrint(arena, "-mcpu={s}", .{mcpu}));
3647 }3656 }
3648 if (create_module.dynamic_linker) |dl| {3657 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 }
3650 }3663 }
3651 try test_exec_args.append(arena, null); // placeholder for the path of the emitted C source file3664 try test_exec_args.append(arena, null); // placeholder for the path of the emitted C source file
3652 }3665 }
...@@ -3793,7 +3806,7 @@ fn createModule(...@@ -3793,7 +3806,7 @@ fn createModule(
3793 .result = target,3806 .result = target,
3794 .is_native_os = target_query.isNativeOs(),3807 .is_native_os = target_query.isNativeOs(),
3795 .is_native_abi = target_query.isNativeAbi(),3808 .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,
3797 };3810 };
3798 };3811 };
37993812
...@@ -3965,6 +3978,7 @@ fn createModule(...@@ -3965,6 +3978,7 @@ fn createModule(
3965 error.WasiExecModelRequiresWasi => fatal("only WASI OS targets support execution model", .{}),3978 error.WasiExecModelRequiresWasi => fatal("only WASI OS targets support execution model", .{}),
3966 error.SharedMemoryIsWasmOnly => fatal("only WebAssembly CPU targets support shared memory", .{}),3979 error.SharedMemoryIsWasmOnly => fatal("only WebAssembly CPU targets support shared memory", .{}),
3967 error.ObjectFilesCannotShareMemory => fatal("object files cannot share memory", .{}),3980 error.ObjectFilesCannotShareMemory => fatal("object files cannot share memory", .{}),
3981 error.ObjectFilesCannotSpecifyDynamicLinker => fatal("object files cannot specify --dynamic-linker", .{}),
3968 error.SharedMemoryRequiresAtomicsAndBulkMemory => fatal("shared memory requires atomics and bulk_memory CPU features", .{}),3982 error.SharedMemoryRequiresAtomicsAndBulkMemory => fatal("shared memory requires atomics and bulk_memory CPU features", .{}),
3969 error.ThreadsRequireSharedMemory => fatal("threads require shared memory", .{}),3983 error.ThreadsRequireSharedMemory => fatal("threads require shared memory", .{}),
3970 error.EmittingLlvmModuleRequiresLlvmBackend => fatal("emitting an LLVM module requires using the LLVM backend", .{}),3984 error.EmittingLlvmModuleRequiresLlvmBackend => fatal("emitting an LLVM module requires using the LLVM backend", .{}),
...@@ -3973,6 +3987,7 @@ fn createModule(...@@ -3973,6 +3987,7 @@ fn createModule(
3973 error.EmittingBinaryRequiresLlvmLibrary => fatal("producing machine code via LLVM requires using the LLVM library", .{}),3987 error.EmittingBinaryRequiresLlvmLibrary => fatal("producing machine code via LLVM requires using the LLVM library", .{}),
3974 error.LldIncompatibleObjectFormat => fatal("using LLD to link {s} files is unsupported", .{@tagName(target.ofmt)}),3988 error.LldIncompatibleObjectFormat => fatal("using LLD to link {s} files is unsupported", .{@tagName(target.ofmt)}),
3975 error.LldCannotIncrementallyLink => fatal("self-hosted backends do not support linking with LLD", .{}),3989 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", .{}),
3976 error.LtoRequiresLld => fatal("LTO requires using LLD", .{}),3991 error.LtoRequiresLld => fatal("LTO requires using LLD", .{}),
3977 error.SanitizeThreadRequiresLibCpp => fatal("thread sanitization is (for now) implemented in C++, so it requires linking libc++", .{}),3992 error.SanitizeThreadRequiresLibCpp => fatal("thread sanitization is (for now) implemented in C++, so it requires linking libc++", .{}),
3978 error.LibCRequiresLibUnwind => fatal("libc of the specified target requires linking libunwind", .{}),3993 error.LibCRequiresLibUnwind => fatal("libc of the specified target requires linking libunwind", .{}),
...@@ -3984,6 +3999,7 @@ fn createModule(...@@ -3984,6 +3999,7 @@ fn createModule(
3984 error.TargetCannotStaticLinkExecutables => fatal("static linking of executables unavailable on the specified target", .{}),3999 error.TargetCannotStaticLinkExecutables => fatal("static linking of executables unavailable on the specified target", .{}),
3985 error.LibCRequiresDynamicLinking => fatal("libc of the specified target requires dynamic linking", .{}),4000 error.LibCRequiresDynamicLinking => fatal("libc of the specified target requires dynamic linking", .{}),
3986 error.SharedLibrariesRequireDynamicLinking => fatal("using shared libraries requires dynamic linking", .{}),4001 error.SharedLibrariesRequireDynamicLinking => fatal("using shared libraries requires dynamic linking", .{}),
4002 error.DynamicLinkingWithLldRequiresSharedLibraries => fatal("dynamic linking with lld requires at least one shared library", .{}),
3987 error.ExportMemoryAndDynamicIncompatible => fatal("exporting memory is incompatible with dynamic linking", .{}),4003 error.ExportMemoryAndDynamicIncompatible => fatal("exporting memory is incompatible with dynamic linking", .{}),
3988 error.DynamicLibraryPrecludesPie => fatal("dynamic libraries cannot be position independent executables", .{}),4004 error.DynamicLibraryPrecludesPie => fatal("dynamic libraries cannot be position independent executables", .{}),
3989 error.TargetRequiresPie => fatal("the specified target requires position independent executables", .{}),4005 error.TargetRequiresPie => fatal("the specified target requires position independent executables", .{}),