authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-11-04 20:58:15+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-11-04 20:58:15+01:00
logf24ceec35a6fd1e5e6a671461b78919b5f588a32
tree00e4242cf5dcdae789e0d8f1de77303f4a2e6e23
parent98dc28bbe223cb7183aabe7ed7a847c67c1a4df9
parent7a186d9eb6a84fb22bdb53b9c81a70169e9fa65f
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #17844 from ziglang/elf-object

elf: handle emitting relocatables and static libraries - humble beginnings

26 files changed, 1913 insertions(+), 1010 deletions(-)

CMakeLists.txt+1-1
...@@ -624,7 +624,7 @@ set(ZIG_STAGE2_SOURCES...@@ -624,7 +624,7 @@ set(ZIG_STAGE2_SOURCES
624 "${CMAKE_SOURCE_DIR}/src/link/Plan9/aout.zig"624 "${CMAKE_SOURCE_DIR}/src/link/Plan9/aout.zig"
625 "${CMAKE_SOURCE_DIR}/src/link/Wasm.zig"625 "${CMAKE_SOURCE_DIR}/src/link/Wasm.zig"
626 "${CMAKE_SOURCE_DIR}/src/link/msdos-stub.bin"626 "${CMAKE_SOURCE_DIR}/src/link/msdos-stub.bin"
627 "${CMAKE_SOURCE_DIR}/src/link/strtab.zig"627 "${CMAKE_SOURCE_DIR}/src/link/StringTable.zig"
628 "${CMAKE_SOURCE_DIR}/src/link/tapi.zig"628 "${CMAKE_SOURCE_DIR}/src/link/tapi.zig"
629 "${CMAKE_SOURCE_DIR}/src/link/tapi/Tokenizer.zig"629 "${CMAKE_SOURCE_DIR}/src/link/tapi/Tokenizer.zig"
630 "${CMAKE_SOURCE_DIR}/src/link/tapi/parse.zig"630 "${CMAKE_SOURCE_DIR}/src/link/tapi/parse.zig"
src/Compilation.zig+59-11
...@@ -810,16 +810,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -810,16 +810,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
810 return error.ExportTableAndImportTableConflict;810 return error.ExportTableAndImportTableConflict;
811 }811 }
812812
813 // The `have_llvm` condition is here only because native backends cannot yet build compiler-rt.
814 // Once they are capable this condition could be removed. When removing this condition,
815 // also test the use case of `build-obj -fcompiler-rt` with the native backends
816 // and make sure the compiler-rt symbols are emitted.
817 const is_p9 = options.target.os.tag == .plan9;
818 const is_spv = options.target.cpu.arch.isSpirV();
819 const capable_of_building_compiler_rt = build_options.have_llvm and !is_p9 and !is_spv;
820 const capable_of_building_zig_libc = build_options.have_llvm and !is_p9 and !is_spv;
821 const capable_of_building_ssp = build_options.have_llvm and !is_p9 and !is_spv;
822
823 const comp: *Compilation = comp: {813 const comp: *Compilation = comp: {
824 // For allocations that have the same lifetime as Compilation. This arena is used only during this814 // For allocations that have the same lifetime as Compilation. This arena is used only during this
825 // initialization and then is freed in deinit().815 // initialization and then is freed in deinit().
...@@ -1094,6 +1084,8 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1094,6 +1084,8 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1094 if (stack_check and !target_util.supportsStackProbing(options.target))1084 if (stack_check and !target_util.supportsStackProbing(options.target))
1095 return error.StackCheckUnsupportedByTarget;1085 return error.StackCheckUnsupportedByTarget;
10961086
1087 const capable_of_building_ssp = canBuildLibSsp(options.target, use_llvm);
1088
1097 const stack_protector: u32 = options.want_stack_protector orelse b: {1089 const stack_protector: u32 = options.want_stack_protector orelse b: {
1098 if (!target_util.supportsStackProtector(options.target)) break :b @as(u32, 0);1090 if (!target_util.supportsStackProtector(options.target)) break :b @as(u32, 0);
10991091
...@@ -1754,6 +1746,9 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1754,6 +1746,9 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
17541746
1755 const target = comp.getTarget();1747 const target = comp.getTarget();
17561748
1749 const capable_of_building_compiler_rt = canBuildLibCompilerRt(target, comp.bin_file.options.use_llvm);
1750 const capable_of_building_zig_libc = canBuildZigLibC(target, comp.bin_file.options.use_llvm);
1751
1757 // Add a `CObject` for each `c_source_files`.1752 // Add a `CObject` for each `c_source_files`.
1758 try comp.c_object_table.ensureTotalCapacity(gpa, options.c_source_files.len);1753 try comp.c_object_table.ensureTotalCapacity(gpa, options.c_source_files.len);
1759 for (options.c_source_files) |c_source_file| {1754 for (options.c_source_files) |c_source_file| {
...@@ -6240,9 +6235,62 @@ pub fn dump_argv(argv: []const []const u8) void {...@@ -6240,9 +6235,62 @@ pub fn dump_argv(argv: []const []const u8) void {
6240 nosuspend stderr.print("{s}\n", .{argv[argv.len - 1]}) catch {};6235 nosuspend stderr.print("{s}\n", .{argv[argv.len - 1]}) catch {};
6241}6236}
62426237
6238fn canBuildLibCompilerRt(target: std.Target, use_llvm: bool) bool {
6239 switch (target.os.tag) {
6240 .plan9 => return false,
6241 else => {},
6242 }
6243 switch (target.cpu.arch) {
6244 .spirv32, .spirv64 => return false,
6245 else => {},
6246 }
6247 return switch (zigBackend(target, use_llvm)) {
6248 .stage2_llvm => true,
6249 .stage2_x86_64 => if (target.ofmt == .elf) true else build_options.have_llvm,
6250 else => build_options.have_llvm,
6251 };
6252}
6253
6254fn canBuildLibSsp(target: std.Target, use_llvm: bool) bool {
6255 switch (target.os.tag) {
6256 .plan9 => return false,
6257 else => {},
6258 }
6259 switch (target.cpu.arch) {
6260 .spirv32, .spirv64 => return false,
6261 else => {},
6262 }
6263 return switch (zigBackend(target, use_llvm)) {
6264 .stage2_llvm => true,
6265 else => build_options.have_llvm,
6266 };
6267}
6268
6269/// Not to be confused with canBuildLibC, which builds musl, glibc, and similar.
6270/// This one builds lib/c.zig.
6271fn canBuildZigLibC(target: std.Target, use_llvm: bool) bool {
6272 switch (target.os.tag) {
6273 .plan9 => return false,
6274 else => {},
6275 }
6276 switch (target.cpu.arch) {
6277 .spirv32, .spirv64 => return false,
6278 else => {},
6279 }
6280 return switch (zigBackend(target, use_llvm)) {
6281 .stage2_llvm => true,
6282 .stage2_x86_64 => if (target.ofmt == .elf) true else build_options.have_llvm,
6283 else => build_options.have_llvm,
6284 };
6285}
6286
6243pub fn getZigBackend(comp: Compilation) std.builtin.CompilerBackend {6287pub fn getZigBackend(comp: Compilation) std.builtin.CompilerBackend {
6244 if (comp.bin_file.options.use_llvm) return .stage2_llvm;
6245 const target = comp.bin_file.options.target;6288 const target = comp.bin_file.options.target;
6289 return zigBackend(target, comp.bin_file.options.use_llvm);
6290}
6291
6292fn zigBackend(target: std.Target, use_llvm: bool) std.builtin.CompilerBackend {
6293 if (use_llvm) return .stage2_llvm;
6246 if (target.ofmt == .c) return .stage2_c;6294 if (target.ofmt == .c) return .stage2_c;
6247 return switch (target.cpu.arch) {6295 return switch (target.cpu.arch) {
6248 .wasm32, .wasm64 => std.builtin.CompilerBackend.stage2_wasm,6296 .wasm32, .wasm64 => std.builtin.CompilerBackend.stage2_wasm,
src/arch/x86_64/CodeGen.zig+2-3
...@@ -10796,7 +10796,7 @@ fn genCall(self: *Self, info: union(enum) {...@@ -10796,7 +10796,7 @@ fn genCall(self: *Self, info: union(enum) {
10796 if (self.bin_file.cast(link.File.Elf)) |elf_file| {10796 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
10797 const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func.owner_decl);10797 const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func.owner_decl);
10798 const sym = elf_file.symbol(sym_index);10798 const sym = elf_file.symbol(sym_index);
10799 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);10799 sym.flags.needs_zig_got = true;
10800 if (self.bin_file.options.pic) {10800 if (self.bin_file.options.pic) {
10801 const callee_reg: Register = switch (resolved_cc) {10801 const callee_reg: Register = switch (resolved_cc) {
10802 .SysV => callee: {10802 .SysV => callee: {
...@@ -13682,8 +13682,7 @@ fn genLazySymbolRef(...@@ -13682,8 +13682,7 @@ fn genLazySymbolRef(
13682 const sym_index = elf_file.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(elf_file, lazy_sym) catch |err|13682 const sym_index = elf_file.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(elf_file, lazy_sym) catch |err|
13683 return self.fail("{s} creating lazy symbol", .{@errorName(err)});13683 return self.fail("{s} creating lazy symbol", .{@errorName(err)});
13684 const sym = elf_file.symbol(sym_index);13684 const sym = elf_file.symbol(sym_index);
13685 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);13685 sym.flags.needs_zig_got = true;
13686
13687 if (self.bin_file.options.pic) {13686 if (self.bin_file.options.pic) {
13688 switch (tag) {13687 switch (tag) {
13689 .lea, .call => try self.genSetReg(reg, Type.usize, .{13688 .lea, .call => try self.genSetReg(reg, Type.usize, .{
src/arch/x86_64/Emit.zig+30-13
...@@ -85,10 +85,19 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -85,10 +85,19 @@ pub fn emitMir(emit: *Emit) Error!void {
85 @tagName(emit.lower.bin_file.tag),85 @tagName(emit.lower.bin_file.tag),
86 }),86 }),
87 .linker_reloc => |data| if (emit.lower.bin_file.cast(link.File.Elf)) |elf_file| {87 .linker_reloc => |data| if (emit.lower.bin_file.cast(link.File.Elf)) |elf_file| {
88 const is_obj_or_static_lib = switch (emit.lower.bin_file.options.output_mode) {
89 .Exe => false,
90 .Obj => true,
91 .Lib => emit.lower.bin_file.options.link_mode == .Static,
92 };
88 const atom = elf_file.symbol(data.atom_index).atom(elf_file).?;93 const atom = elf_file.symbol(data.atom_index).atom(elf_file).?;
89 const sym = elf_file.symbol(elf_file.zigObjectPtr().?.symbol(data.sym_index));94 const sym_index = elf_file.zigObjectPtr().?.symbol(data.sym_index);
95 const sym = elf_file.symbol(sym_index);
96 if (sym.flags.needs_zig_got and !is_obj_or_static_lib) {
97 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
98 }
90 if (emit.lower.bin_file.options.pic) {99 if (emit.lower.bin_file.options.pic) {
91 const r_type: u32 = if (sym.flags.has_zig_got)100 const r_type: u32 = if (sym.flags.needs_zig_got and !is_obj_or_static_lib)
92 link.File.Elf.R_X86_64_ZIG_GOTPCREL101 link.File.Elf.R_X86_64_ZIG_GOTPCREL
93 else if (sym.flags.needs_got)102 else if (sym.flags.needs_got)
94 std.elf.R_X86_64_GOTPCREL103 std.elf.R_X86_64_GOTPCREL
...@@ -100,17 +109,25 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -100,17 +109,25 @@ pub fn emitMir(emit: *Emit) Error!void {
100 .r_addend = -4,109 .r_addend = -4,
101 });110 });
102 } else {111 } else {
103 const r_type: u32 = if (sym.flags.has_zig_got)112 if (lowered_inst.encoding.mnemonic == .call and sym.flags.needs_zig_got and is_obj_or_static_lib) {
104 link.File.Elf.R_X86_64_ZIG_GOT32113 try atom.addReloc(elf_file, .{
105 else if (sym.flags.needs_got)114 .r_offset = end_offset - 4,
106 std.elf.R_X86_64_GOT32115 .r_info = (@as(u64, @intCast(data.sym_index)) << 32) | std.elf.R_X86_64_PC32,
107 else116 .r_addend = -4,
108 std.elf.R_X86_64_32;117 });
109 try atom.addReloc(elf_file, .{118 } else {
110 .r_offset = end_offset - 4,119 const r_type: u32 = if (sym.flags.needs_zig_got and !is_obj_or_static_lib)
111 .r_info = (@as(u64, @intCast(data.sym_index)) << 32) | r_type,120 link.File.Elf.R_X86_64_ZIG_GOT32
112 .r_addend = 0,121 else if (sym.flags.needs_got)
113 });122 std.elf.R_X86_64_GOT32
123 else
124 std.elf.R_X86_64_32;
125 try atom.addReloc(elf_file, .{
126 .r_offset = end_offset - 4,
127 .r_info = (@as(u64, @intCast(data.sym_index)) << 32) | r_type,
128 .r_addend = 0,
129 });
130 }
114 }131 }
115 } else unreachable,132 } else unreachable,
116 .linker_got,133 .linker_got,
src/arch/x86_64/Lower.zig+29-5
...@@ -319,6 +319,19 @@ fn reloc(lower: *Lower, target: Reloc.Target) Immediate {...@@ -319,6 +319,19 @@ fn reloc(lower: *Lower, target: Reloc.Target) Immediate {
319}319}
320320
321fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) Error!void {321fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) Error!void {
322 const needsZigGot = struct {
323 fn needsZigGot(sym: bits.Symbol, ctx: *link.File) bool {
324 const elf_file = ctx.cast(link.File.Elf).?;
325 const sym_index = elf_file.zigObjectPtr().?.symbol(sym.sym_index);
326 return elf_file.symbol(sym_index).flags.needs_zig_got;
327 }
328 }.needsZigGot;
329
330 const is_obj_or_static_lib = switch (lower.bin_file.options.output_mode) {
331 .Exe => false,
332 .Obj => true,
333 .Lib => lower.bin_file.options.link_mode == .Static,
334 };
322 var emit_prefix = prefix;335 var emit_prefix = prefix;
323 var emit_mnemonic = mnemonic;336 var emit_mnemonic = mnemonic;
324 var emit_ops_storage: [4]Operand = undefined;337 var emit_ops_storage: [4]Operand = undefined;
...@@ -334,19 +347,30 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)...@@ -334,19 +347,30 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
334 assert(mem_op.sib.scale_index.scale == 0);347 assert(mem_op.sib.scale_index.scale == 0);
335 _ = lower.reloc(.{ .linker_reloc = sym });348 _ = lower.reloc(.{ .linker_reloc = sym });
336 break :op if (lower.bin_file.options.pic) switch (mnemonic) {349 break :op if (lower.bin_file.options.pic) switch (mnemonic) {
337 .mov, .lea => .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) },350 .lea => {
351 break :op .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) };
352 },
353 .mov => {
354 if (is_obj_or_static_lib and needsZigGot(sym, lower.bin_file)) emit_mnemonic = .lea;
355 break :op .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) };
356 },
338 else => unreachable,357 else => unreachable,
339 } else switch (mnemonic) {358 } else switch (mnemonic) {
340 .call => .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{359 .call => break :op if (is_obj_or_static_lib and needsZigGot(sym, lower.bin_file)) .{
360 .imm = Immediate.s(0),
361 } else .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{
341 .base = .{ .reg = .ds },362 .base = .{ .reg = .ds },
342 }) },363 }) },
343 .lea => {364 .lea => {
344 emit_mnemonic = .mov;365 emit_mnemonic = .mov;
345 break :op .{ .imm = Immediate.s(0) };366 break :op .{ .imm = Immediate.s(0) };
346 },367 },
347 .mov => .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{368 .mov => {
348 .base = .{ .reg = .ds },369 if (is_obj_or_static_lib and needsZigGot(sym, lower.bin_file)) emit_mnemonic = .lea;
349 }) },370 break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{
371 .base = .{ .reg = .ds },
372 }) };
373 },
350 else => unreachable,374 else => unreachable,
351 };375 };
352 },376 },
src/codegen.zig+1-1
...@@ -912,7 +912,7 @@ fn genDeclRef(...@@ -912,7 +912,7 @@ fn genDeclRef(
912 }912 }
913 const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, decl_index);913 const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, decl_index);
914 const sym = elf_file.symbol(sym_index);914 const sym = elf_file.symbol(sym_index);
915 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);915 sym.flags.needs_zig_got = true;
916 return GenResult.mcv(.{ .load_symbol = sym.esym_index });916 return GenResult.mcv(.{ .load_symbol = sym.esym_index });
917 } else if (bin_file.cast(link.File.MachO)) |macho_file| {917 } else if (bin_file.cast(link.File.MachO)) |macho_file| {
918 if (is_extern) {918 if (is_extern) {
src/link/Coff.zig+8-8
...@@ -33,10 +33,10 @@ need_got_table: std.AutoHashMapUnmanaged(u32, void) = .{},...@@ -33,10 +33,10 @@ need_got_table: std.AutoHashMapUnmanaged(u32, void) = .{},
33locals_free_list: std.ArrayListUnmanaged(u32) = .{},33locals_free_list: std.ArrayListUnmanaged(u32) = .{},
34globals_free_list: std.ArrayListUnmanaged(u32) = .{},34globals_free_list: std.ArrayListUnmanaged(u32) = .{},
3535
36strtab: StringTable(.strtab) = .{},36strtab: StringTable = .{},
37strtab_offset: ?u32 = null,37strtab_offset: ?u32 = null,
3838
39temp_strtab: StringTable(.temp_strtab) = .{},39temp_strtab: StringTable = .{},
4040
41got_table: TableSection(SymbolWithLoc) = .{},41got_table: TableSection(SymbolWithLoc) = .{},
4242
...@@ -419,7 +419,7 @@ fn populateMissingMetadata(self: *Coff) !void {...@@ -419,7 +419,7 @@ fn populateMissingMetadata(self: *Coff) !void {
419 }419 }
420420
421 if (self.strtab_offset == null) {421 if (self.strtab_offset == null) {
422 const file_size = @as(u32, @intCast(self.strtab.len()));422 const file_size = @as(u32, @intCast(self.strtab.buffer.items.len));
423 self.strtab_offset = self.findFreeSpace(file_size, @alignOf(u32)); // 4bytes aligned seems like a good idea here423 self.strtab_offset = self.findFreeSpace(file_size, @alignOf(u32)); // 4bytes aligned seems like a good idea here
424 log.debug("found strtab free space 0x{x} to 0x{x}", .{ self.strtab_offset.?, self.strtab_offset.? + file_size });424 log.debug("found strtab free space 0x{x} to 0x{x}", .{ self.strtab_offset.?, self.strtab_offset.? + file_size });
425 }425 }
...@@ -2143,7 +2143,7 @@ fn writeStrtab(self: *Coff) !void {...@@ -2143,7 +2143,7 @@ fn writeStrtab(self: *Coff) !void {
2143 if (self.strtab_offset == null) return;2143 if (self.strtab_offset == null) return;
21442144
2145 const allocated_size = self.allocatedSize(self.strtab_offset.?);2145 const allocated_size = self.allocatedSize(self.strtab_offset.?);
2146 const needed_size = @as(u32, @intCast(self.strtab.len()));2146 const needed_size = @as(u32, @intCast(self.strtab.buffer.items.len));
21472147
2148 if (needed_size > allocated_size) {2148 if (needed_size > allocated_size) {
2149 self.strtab_offset = null;2149 self.strtab_offset = null;
...@@ -2155,10 +2155,10 @@ fn writeStrtab(self: *Coff) !void {...@@ -2155,10 +2155,10 @@ fn writeStrtab(self: *Coff) !void {
2155 var buffer = std.ArrayList(u8).init(self.base.allocator);2155 var buffer = std.ArrayList(u8).init(self.base.allocator);
2156 defer buffer.deinit();2156 defer buffer.deinit();
2157 try buffer.ensureTotalCapacityPrecise(needed_size);2157 try buffer.ensureTotalCapacityPrecise(needed_size);
2158 buffer.appendSliceAssumeCapacity(self.strtab.items());2158 buffer.appendSliceAssumeCapacity(self.strtab.buffer.items);
2159 // Here, we do a trick in that we do not commit the size of the strtab to strtab buffer, instead2159 // Here, we do a trick in that we do not commit the size of the strtab to strtab buffer, instead
2160 // we write the length of the strtab to a temporary buffer that goes to file.2160 // we write the length of the strtab to a temporary buffer that goes to file.
2161 mem.writeInt(u32, buffer.items[0..4], @as(u32, @intCast(self.strtab.len())), .little);2161 mem.writeInt(u32, buffer.items[0..4], @as(u32, @intCast(self.strtab.buffer.items.len)), .little);
21622162
2163 try self.base.file.?.pwriteAll(buffer.items, self.strtab_offset.?);2163 try self.base.file.?.pwriteAll(buffer.items, self.strtab_offset.?);
2164}2164}
...@@ -2326,7 +2326,7 @@ fn detectAllocCollision(self: *Coff, start: u32, size: u32) ?u32 {...@@ -2326,7 +2326,7 @@ fn detectAllocCollision(self: *Coff, start: u32, size: u32) ?u32 {
2326 const end = start + padToIdeal(size);2326 const end = start + padToIdeal(size);
23272327
2328 if (self.strtab_offset) |off| {2328 if (self.strtab_offset) |off| {
2329 const tight_size = @as(u32, @intCast(self.strtab.len()));2329 const tight_size = @as(u32, @intCast(self.strtab.buffer.items.len));
2330 const increased_size = padToIdeal(tight_size);2330 const increased_size = padToIdeal(tight_size);
2331 const test_end = off + increased_size;2331 const test_end = off + increased_size;
2332 if (end > off and start < test_end) {2332 if (end > off and start < test_end) {
...@@ -2667,7 +2667,7 @@ const InternPool = @import("../InternPool.zig");...@@ -2667,7 +2667,7 @@ const InternPool = @import("../InternPool.zig");
2667const Object = @import("Coff/Object.zig");2667const Object = @import("Coff/Object.zig");
2668const Relocation = @import("Coff/Relocation.zig");2668const Relocation = @import("Coff/Relocation.zig");
2669const TableSection = @import("table_section.zig").TableSection;2669const TableSection = @import("table_section.zig").TableSection;
2670const StringTable = @import("strtab.zig").StringTable;2670const StringTable = @import("StringTable.zig");
2671const Type = @import("../type.zig").Type;2671const Type = @import("../type.zig").Type;
2672const TypedValue = @import("../TypedValue.zig");2672const TypedValue = @import("../TypedValue.zig");
26732673
src/link/Dwarf.zig+2-2
...@@ -23,7 +23,7 @@ abbrev_table_offset: ?u64 = null,...@@ -23,7 +23,7 @@ abbrev_table_offset: ?u64 = null,
2323
24/// TODO replace with InternPool24/// TODO replace with InternPool
25/// Table of debug symbol names.25/// Table of debug symbol names.
26strtab: StringTable(.strtab) = .{},26strtab: StringTable = .{},
2727
28/// Quick lookup array of all defined source files referenced by at least one Decl.28/// Quick lookup array of all defined source files referenced by at least one Decl.
29/// They will end up in the DWARF debug_line header as two lists:29/// They will end up in the DWARF debug_line header as two lists:
...@@ -2760,6 +2760,6 @@ const LinkFn = File.LinkFn;...@@ -2760,6 +2760,6 @@ const LinkFn = File.LinkFn;
2760const LinkerLoad = @import("../codegen.zig").LinkerLoad;2760const LinkerLoad = @import("../codegen.zig").LinkerLoad;
2761const Module = @import("../Module.zig");2761const Module = @import("../Module.zig");
2762const InternPool = @import("../InternPool.zig");2762const InternPool = @import("../InternPool.zig");
2763const StringTable = @import("strtab.zig").StringTable;2763const StringTable = @import("StringTable.zig");
2764const Type = @import("../type.zig").Type;2764const Type = @import("../type.zig").Type;
2765const Value = @import("../value.zig").Value;2765const Value = @import("../value.zig").Value;
src/link/Elf.zig+647-346
...@@ -66,13 +66,15 @@ page_size: u32,...@@ -66,13 +66,15 @@ page_size: u32,
66default_sym_version: elf.Elf64_Versym,66default_sym_version: elf.Elf64_Versym,
6767
68/// .shstrtab buffer68/// .shstrtab buffer
69shstrtab: StringTable(.strtab) = .{},69shstrtab: std.ArrayListUnmanaged(u8) = .{},
70/// .symtab buffer
71symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
70/// .strtab buffer72/// .strtab buffer
71strtab: StringTable(.strtab) = .{},73strtab: std.ArrayListUnmanaged(u8) = .{},
72/// Dynamic symbol table. Only populated and emitted when linking dynamically.74/// Dynamic symbol table. Only populated and emitted when linking dynamically.
73dynsym: DynsymSection = .{},75dynsym: DynsymSection = .{},
74/// .dynstrtab buffer76/// .dynstrtab buffer
75dynstrtab: StringTable(.dynstrtab) = .{},77dynstrtab: std.ArrayListUnmanaged(u8) = .{},
76/// Version symbol table. Only populated and emitted when linking dynamically.78/// Version symbol table. Only populated and emitted when linking dynamically.
77versym: std.ArrayListUnmanaged(elf.Elf64_Versym) = .{},79versym: std.ArrayListUnmanaged(elf.Elf64_Versym) = .{},
78/// .verneed section80/// .verneed section
...@@ -97,13 +99,17 @@ plt_got: PltGotSection = .{},...@@ -97,13 +99,17 @@ plt_got: PltGotSection = .{},
97copy_rel: CopyRelSection = .{},99copy_rel: CopyRelSection = .{},
98/// .rela.plt section100/// .rela.plt section
99rela_plt: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{},101rela_plt: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{},
100/// .zig.got section102/// .got.zig section
101zig_got: ZigGotSection = .{},103zig_got: ZigGotSection = .{},
102104
103/// Tracked section headers with incremental updates to Zig object105/// Tracked section headers with incremental updates to Zig object.
106/// .rela.* sections are only used when emitting a relocatable object file.
104zig_text_section_index: ?u16 = null,107zig_text_section_index: ?u16 = null,
105zig_rodata_section_index: ?u16 = null,108zig_text_rela_section_index: ?u16 = null,
109zig_data_rel_ro_section_index: ?u16 = null,
110zig_data_rel_ro_rela_section_index: ?u16 = null,
106zig_data_section_index: ?u16 = null,111zig_data_section_index: ?u16 = null,
112zig_data_rela_section_index: ?u16 = null,
107zig_bss_section_index: ?u16 = null,113zig_bss_section_index: ?u16 = null,
108zig_got_section_index: ?u16 = null,114zig_got_section_index: ?u16 = null,
109115
...@@ -156,9 +162,10 @@ start_stop_indexes: std.ArrayListUnmanaged(u32) = .{},...@@ -156,9 +162,10 @@ start_stop_indexes: std.ArrayListUnmanaged(u32) = .{},
156/// An array of symbols parsed across all input files.162/// An array of symbols parsed across all input files.
157symbols: std.ArrayListUnmanaged(Symbol) = .{},163symbols: std.ArrayListUnmanaged(Symbol) = .{},
158symbols_extra: std.ArrayListUnmanaged(u32) = .{},164symbols_extra: std.ArrayListUnmanaged(u32) = .{},
159resolver: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index) = .{},
160symbols_free_list: std.ArrayListUnmanaged(Symbol.Index) = .{},165symbols_free_list: std.ArrayListUnmanaged(Symbol.Index) = .{},
161166
167resolver: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index) = .{},
168
162has_text_reloc: bool = false,169has_text_reloc: bool = false,
163num_ifunc_dynrelocs: usize = 0,170num_ifunc_dynrelocs: usize = 0,
164171
...@@ -175,6 +182,10 @@ comdat_groups: std.ArrayListUnmanaged(ComdatGroup) = .{},...@@ -175,6 +182,10 @@ comdat_groups: std.ArrayListUnmanaged(ComdatGroup) = .{},
175comdat_groups_owners: std.ArrayListUnmanaged(ComdatGroupOwner) = .{},182comdat_groups_owners: std.ArrayListUnmanaged(ComdatGroupOwner) = .{},
176comdat_groups_table: std.AutoHashMapUnmanaged(u32, ComdatGroupOwner.Index) = .{},183comdat_groups_table: std.AutoHashMapUnmanaged(u32, ComdatGroupOwner.Index) = .{},
177184
185/// Global string table used to provide quick access to global symbol resolvers
186/// such as `resolver` and `comdat_groups_table`.
187strings: StringTable = .{},
188
178/// When allocating, the ideal_capacity is calculated by189/// When allocating, the ideal_capacity is calculated by
179/// actual_capacity + (actual_capacity / ideal_factor)190/// actual_capacity + (actual_capacity / ideal_factor)
180const ideal_factor = 3;191const ideal_factor = 3;
...@@ -227,13 +238,15 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option...@@ -227,13 +238,15 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
227 // Append null file at index 0238 // Append null file at index 0
228 try self.files.append(allocator, .null);239 try self.files.append(allocator, .null);
229 // Append null byte to string tables240 // Append null byte to string tables
230 try self.shstrtab.buffer.append(allocator, 0);241 try self.shstrtab.append(allocator, 0);
231 try self.strtab.buffer.append(allocator, 0);242 try self.strtab.append(allocator, 0);
232 // There must always be a null shdr in index 0243 // There must always be a null shdr in index 0
233 _ = try self.addSection(.{ .name = "" });244 _ = try self.addSection(.{ .name = "" });
245 // Append null symbol in output symtab
246 try self.symtab.append(allocator, null_sym);
234247
235 if (!is_obj_or_ar) {248 if (!is_obj_or_ar) {
236 try self.dynstrtab.buffer.append(allocator, 0);249 try self.dynstrtab.append(allocator, 0);
237250
238 // Initialize PT_PHDR program header251 // Initialize PT_PHDR program header
239 const p_align: u16 = switch (self.ptr_width) {252 const p_align: u16 = switch (self.ptr_width) {
...@@ -347,6 +360,7 @@ pub fn deinit(self: *Elf) void {...@@ -347,6 +360,7 @@ pub fn deinit(self: *Elf) void {
347 }360 }
348 self.output_sections.deinit(gpa);361 self.output_sections.deinit(gpa);
349 self.shstrtab.deinit(gpa);362 self.shstrtab.deinit(gpa);
363 self.symtab.deinit(gpa);
350 self.strtab.deinit(gpa);364 self.strtab.deinit(gpa);
351 self.symbols.deinit(gpa);365 self.symbols.deinit(gpa);
352 self.symbols_extra.deinit(gpa);366 self.symbols_extra.deinit(gpa);
...@@ -364,6 +378,7 @@ pub fn deinit(self: *Elf) void {...@@ -364,6 +378,7 @@ pub fn deinit(self: *Elf) void {
364 self.comdat_groups.deinit(gpa);378 self.comdat_groups.deinit(gpa);
365 self.comdat_groups_owners.deinit(gpa);379 self.comdat_groups_owners.deinit(gpa);
366 self.comdat_groups_table.deinit(gpa);380 self.comdat_groups_table.deinit(gpa);
381 self.strings.deinit(gpa);
367382
368 self.got.deinit(gpa);383 self.got.deinit(gpa);
369 self.plt.deinit(gpa);384 self.plt.deinit(gpa);
...@@ -473,262 +488,302 @@ fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u64) u64 {...@@ -473,262 +488,302 @@ fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u64) u64 {
473 return start;488 return start;
474}489}
475490
476const AllocateSegmentOpts = struct {
477 addr: u64,
478 memsz: u64,
479 filesz: u64,
480 alignment: u64,
481 flags: u32 = elf.PF_R,
482};
483
484pub fn allocateSegment(self: *Elf, opts: AllocateSegmentOpts) error{OutOfMemory}!u16 {
485 const off = self.findFreeSpace(opts.filesz, opts.alignment);
486 const index = try self.addPhdr(.{
487 .type = elf.PT_LOAD,
488 .offset = off,
489 .filesz = opts.filesz,
490 .addr = opts.addr,
491 .memsz = opts.memsz,
492 .@"align" = opts.alignment,
493 .flags = opts.flags,
494 });
495 log.debug("allocating phdr({d})({c}{c}{c}) from 0x{x} to 0x{x} (0x{x} - 0x{x})", .{
496 index,
497 if (opts.flags & elf.PF_R != 0) @as(u8, 'R') else '_',
498 if (opts.flags & elf.PF_W != 0) @as(u8, 'W') else '_',
499 if (opts.flags & elf.PF_X != 0) @as(u8, 'X') else '_',
500 off,
501 off + opts.filesz,
502 opts.addr,
503 opts.addr + opts.memsz,
504 });
505 return index;
506}
507
508const AllocateAllocSectionOpts = struct {
509 name: [:0]const u8,
510 phdr_index: u16,
511 alignment: u64 = 1,
512 flags: u64 = elf.SHF_ALLOC,
513 type: u32 = elf.SHT_PROGBITS,
514};
515
516pub fn allocateAllocSection(self: *Elf, opts: AllocateAllocSectionOpts) error{OutOfMemory}!u16 {
517 const gpa = self.base.allocator;
518 const phdr = &self.phdrs.items[opts.phdr_index];
519 const index = try self.addSection(.{
520 .name = opts.name,
521 .type = opts.type,
522 .flags = opts.flags,
523 .addralign = opts.alignment,
524 .offset = std.math.maxInt(u64),
525 });
526 const shdr = &self.shdrs.items[index];
527 try self.phdr_to_shdr_table.putNoClobber(gpa, index, opts.phdr_index);
528 log.debug("allocating '{s}' in phdr({d}) from 0x{x} to 0x{x} (0x{x} - 0x{x})", .{
529 opts.name,
530 opts.phdr_index,
531 phdr.p_offset,
532 phdr.p_offset + phdr.p_filesz,
533 phdr.p_vaddr,
534 phdr.p_vaddr + phdr.p_memsz,
535 });
536 shdr.sh_addr = phdr.p_vaddr;
537 shdr.sh_offset = phdr.p_offset;
538 shdr.sh_size = phdr.p_memsz;
539 return index;
540}
541
542const AllocateNonAllocSectionOpts = struct {
543 name: [:0]const u8,
544 size: u64,
545 alignment: u16 = 1,
546 flags: u32 = 0,
547 type: u32 = elf.SHT_PROGBITS,
548 link: u32 = 0,
549 info: u32 = 0,
550 entsize: u64 = 0,
551};
552
553fn allocateNonAllocSection(self: *Elf, opts: AllocateNonAllocSectionOpts) error{OutOfMemory}!u16 {
554 const index = try self.addSection(.{
555 .name = opts.name,
556 .type = opts.type,
557 .flags = opts.flags,
558 .link = opts.link,
559 .info = opts.info,
560 .addralign = opts.alignment,
561 .entsize = opts.entsize,
562 .offset = std.math.maxInt(u64),
563 });
564 const shdr = &self.shdrs.items[index];
565 const off = self.findFreeSpace(opts.size, opts.alignment);
566 log.debug("allocating '{s}' from 0x{x} to 0x{x} ", .{ opts.name, off, off + opts.size });
567 shdr.sh_offset = off;
568 shdr.sh_size = opts.size;
569 return index;
570}
571
572/// TODO move to ZigObject491/// TODO move to ZigObject
573pub fn initMetadata(self: *Elf) !void {492pub fn initMetadata(self: *Elf) !void {
574 const gpa = self.base.allocator;493 const gpa = self.base.allocator;
575 const ptr_size = self.ptrWidthBytes();494 const ptr_size = self.ptrWidthBytes();
576 const ptr_bit_width = self.base.options.target.ptrBitWidth();495 const ptr_bit_width = self.base.options.target.ptrBitWidth();
577 const is_linux = self.base.options.target.os.tag == .linux;496 const is_linux = self.base.options.target.os.tag == .linux;
497 const zig_object = self.zigObjectPtr().?;
498
499 const fillSection = struct {
500 fn fillSection(elf_file: *Elf, shdr: *elf.Elf64_Shdr, size: u64, phndx: ?u16) void {
501 if (elf_file.isRelocatable()) {
502 const off = elf_file.findFreeSpace(size, shdr.sh_addralign);
503 shdr.sh_offset = off;
504 shdr.sh_size = size;
505 } else {
506 const phdr = elf_file.phdrs.items[phndx.?];
507 shdr.sh_addr = phdr.p_vaddr;
508 shdr.sh_offset = phdr.p_offset;
509 shdr.sh_size = phdr.p_memsz;
510 }
511 }
512 }.fillSection;
578513
579 comptime assert(number_of_zig_segments == 5);514 comptime assert(number_of_zig_segments == 5);
580515
581 if (self.phdr_zig_load_re_index == null) {516 if (!self.isRelocatable()) {
582 self.phdr_zig_load_re_index = try self.allocateSegment(.{517 if (self.phdr_zig_load_re_index == null) {
583 .addr = if (ptr_bit_width >= 32) 0x8000000 else 0x8000,518 const filesz = self.base.options.program_code_size_hint;
584 .memsz = self.base.options.program_code_size_hint,519 const off = self.findFreeSpace(filesz, self.page_size);
585 .filesz = self.base.options.program_code_size_hint,520 self.phdr_zig_load_re_index = try self.addPhdr(.{
586 .alignment = self.page_size,521 .type = elf.PT_LOAD,
587 .flags = elf.PF_X | elf.PF_R | elf.PF_W,522 .offset = off,
588 });523 .filesz = filesz,
589 }524 .addr = if (ptr_bit_width >= 32) 0x8000000 else 0x8000,
525 .memsz = filesz,
526 .@"align" = self.page_size,
527 .flags = elf.PF_X | elf.PF_R | elf.PF_W,
528 });
529 }
590530
591 if (self.phdr_zig_got_index == null) {531 if (self.phdr_zig_got_index == null) {
592 // We really only need ptr alignment but since we are using PROGBITS, linux requires532 // We really only need ptr alignment but since we are using PROGBITS, linux requires
593 // page align.533 // page align.
594 const alignment = if (is_linux) self.page_size else @as(u16, ptr_size);534 const alignment = if (is_linux) self.page_size else @as(u16, ptr_size);
595 self.phdr_zig_got_index = try self.allocateSegment(.{535 const filesz = @as(u64, ptr_size) * self.base.options.symbol_count_hint;
596 .addr = if (ptr_bit_width >= 32) 0x4000000 else 0x4000,536 const off = self.findFreeSpace(filesz, alignment);
597 .memsz = @as(u64, ptr_size) * self.base.options.symbol_count_hint,537 self.phdr_zig_got_index = try self.addPhdr(.{
598 .filesz = @as(u64, ptr_size) * self.base.options.symbol_count_hint,538 .type = elf.PT_LOAD,
599 .alignment = alignment,539 .offset = off,
600 .flags = elf.PF_R | elf.PF_W,540 .filesz = filesz,
601 });541 .addr = if (ptr_bit_width >= 32) 0x4000000 else 0x4000,
602 }542 .memsz = filesz,
543 .@"align" = alignment,
544 .flags = elf.PF_R | elf.PF_W,
545 });
546 }
603547
604 if (self.phdr_zig_load_ro_index == null) {548 if (self.phdr_zig_load_ro_index == null) {
605 const alignment = if (is_linux) self.page_size else @as(u16, ptr_size);549 const alignment = if (is_linux) self.page_size else @as(u16, ptr_size);
606 self.phdr_zig_load_ro_index = try self.allocateSegment(.{550 const filesz: u64 = 1024;
607 .addr = if (ptr_bit_width >= 32) 0xc000000 else 0xa000,551 const off = self.findFreeSpace(filesz, alignment);
608 .memsz = 1024,552 self.phdr_zig_load_ro_index = try self.addPhdr(.{
609 .filesz = 1024,553 .type = elf.PT_LOAD,
610 .alignment = alignment,554 .offset = off,
611 .flags = elf.PF_R | elf.PF_W,555 .filesz = filesz,
612 });556 .addr = if (ptr_bit_width >= 32) 0xc000000 else 0xa000,
613 }557 .memsz = filesz,
558 .@"align" = alignment,
559 .flags = elf.PF_R | elf.PF_W,
560 });
561 }
614562
615 if (self.phdr_zig_load_rw_index == null) {563 if (self.phdr_zig_load_rw_index == null) {
616 const alignment = if (is_linux) self.page_size else @as(u16, ptr_size);564 const alignment = if (is_linux) self.page_size else @as(u16, ptr_size);
617 self.phdr_zig_load_rw_index = try self.allocateSegment(.{565 const filesz: u64 = 1024;
618 .addr = if (ptr_bit_width >= 32) 0x10000000 else 0xc000,566 const off = self.findFreeSpace(filesz, alignment);
619 .memsz = 1024,567 self.phdr_zig_load_rw_index = try self.addPhdr(.{
620 .filesz = 1024,568 .type = elf.PT_LOAD,
621 .alignment = alignment,569 .offset = off,
622 .flags = elf.PF_R | elf.PF_W,570 .filesz = filesz,
623 });571 .addr = if (ptr_bit_width >= 32) 0x10000000 else 0xc000,
624 }572 .memsz = filesz,
573 .@"align" = alignment,
574 .flags = elf.PF_R | elf.PF_W,
575 });
576 }
625577
626 if (self.phdr_zig_load_zerofill_index == null) {578 if (self.phdr_zig_load_zerofill_index == null) {
627 const alignment = if (is_linux) self.page_size else @as(u16, ptr_size);579 const alignment = if (is_linux) self.page_size else @as(u16, ptr_size);
628 self.phdr_zig_load_zerofill_index = try self.addPhdr(.{580 self.phdr_zig_load_zerofill_index = try self.addPhdr(.{
629 .type = elf.PT_LOAD,581 .type = elf.PT_LOAD,
630 .addr = if (ptr_bit_width >= 32) 0x14000000 else 0xf000,582 .addr = if (ptr_bit_width >= 32) 0x14000000 else 0xf000,
631 .memsz = 1024,583 .memsz = 1024,
632 .@"align" = alignment,584 .@"align" = alignment,
633 .flags = elf.PF_R | elf.PF_W,585 .flags = elf.PF_R | elf.PF_W,
634 });586 });
587 }
635 }588 }
636589
637 if (self.zig_text_section_index == null) {590 if (self.zig_text_section_index == null) {
638 self.zig_text_section_index = try self.allocateAllocSection(.{591 self.zig_text_section_index = try self.addSection(.{
639 .name = ".zig.text",592 .name = ".text.zig",
640 .phdr_index = self.phdr_zig_load_re_index.?,593 .type = elf.SHT_PROGBITS,
641 .flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,594 .flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,
595 .addralign = 1,
596 .offset = std.math.maxInt(u64),
642 });597 });
598 const shdr = &self.shdrs.items[self.zig_text_section_index.?];
599 fillSection(self, shdr, self.base.options.program_code_size_hint, self.phdr_zig_load_re_index);
600 if (self.isRelocatable()) {
601 try zig_object.addSectionSymbol(self.zig_text_section_index.?, self);
602 self.zig_text_rela_section_index = try self.addRelaShdr(
603 ".rela.text.zig",
604 self.zig_text_section_index.?,
605 );
606 } else {
607 try self.phdr_to_shdr_table.putNoClobber(
608 gpa,
609 self.zig_text_section_index.?,
610 self.phdr_zig_load_re_index.?,
611 );
612 }
643 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_text_section_index.?, .{});613 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_text_section_index.?, .{});
644 }614 }
645615
646 if (self.zig_got_section_index == null) {616 if (self.zig_got_section_index == null and !self.isRelocatable()) {
647 self.zig_got_section_index = try self.allocateAllocSection(.{617 self.zig_got_section_index = try self.addSection(.{
648 .name = ".zig.got",618 .name = ".got.zig",
649 .phdr_index = self.phdr_zig_got_index.?,619 .type = elf.SHT_PROGBITS,
650 .alignment = ptr_size,620 .addralign = ptr_size,
651 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,621 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
622 .offset = std.math.maxInt(u64),
652 });623 });
653 }624 const shdr = &self.shdrs.items[self.zig_got_section_index.?];
654625 const phndx = self.phdr_zig_got_index.?;
655 if (self.zig_rodata_section_index == null) {626 const phdr = self.phdrs.items[phndx];
656 self.zig_rodata_section_index = try self.allocateAllocSection(.{627 shdr.sh_addr = phdr.p_vaddr;
657 .name = ".zig.rodata",628 shdr.sh_offset = phdr.p_offset;
658 .phdr_index = self.phdr_zig_load_ro_index.?,629 shdr.sh_size = phdr.p_memsz;
630 try self.phdr_to_shdr_table.putNoClobber(
631 gpa,
632 self.zig_got_section_index.?,
633 self.phdr_zig_got_index.?,
634 );
635 }
636
637 if (self.zig_data_rel_ro_section_index == null) {
638 self.zig_data_rel_ro_section_index = try self.addSection(.{
639 .name = ".data.rel.ro.zig",
640 .type = elf.SHT_PROGBITS,
641 .addralign = 1,
659 .flags = elf.SHF_ALLOC | elf.SHF_WRITE, // TODO rename this section to .data.rel.ro642 .flags = elf.SHF_ALLOC | elf.SHF_WRITE, // TODO rename this section to .data.rel.ro
643 .offset = std.math.maxInt(u64),
660 });644 });
661 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_rodata_section_index.?, .{});645 const shdr = &self.shdrs.items[self.zig_data_rel_ro_section_index.?];
646 fillSection(self, shdr, 1024, self.phdr_zig_load_ro_index);
647 if (self.isRelocatable()) {
648 try zig_object.addSectionSymbol(self.zig_data_rel_ro_section_index.?, self);
649 self.zig_data_rel_ro_rela_section_index = try self.addRelaShdr(
650 ".rela.data.rel.ro.zig",
651 self.zig_data_rel_ro_section_index.?,
652 );
653 } else {
654 try self.phdr_to_shdr_table.putNoClobber(
655 gpa,
656 self.zig_data_rel_ro_section_index.?,
657 self.phdr_zig_load_ro_index.?,
658 );
659 }
660 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_data_rel_ro_section_index.?, .{});
662 }661 }
663662
664 if (self.zig_data_section_index == null) {663 if (self.zig_data_section_index == null) {
665 self.zig_data_section_index = try self.allocateAllocSection(.{664 self.zig_data_section_index = try self.addSection(.{
666 .name = ".zig.data",665 .name = ".data.zig",
667 .phdr_index = self.phdr_zig_load_rw_index.?,666 .type = elf.SHT_PROGBITS,
668 .alignment = ptr_size,667 .addralign = ptr_size,
669 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,668 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
669 .offset = std.math.maxInt(u64),
670 });670 });
671 const shdr = &self.shdrs.items[self.zig_data_section_index.?];
672 fillSection(self, shdr, 1024, self.phdr_zig_load_rw_index);
673 if (self.isRelocatable()) {
674 try zig_object.addSectionSymbol(self.zig_data_section_index.?, self);
675 self.zig_data_rela_section_index = try self.addRelaShdr(
676 ".rela.data.zig",
677 self.zig_data_section_index.?,
678 );
679 } else {
680 try self.phdr_to_shdr_table.putNoClobber(
681 gpa,
682 self.zig_data_section_index.?,
683 self.phdr_zig_load_rw_index.?,
684 );
685 }
671 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_data_section_index.?, .{});686 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_data_section_index.?, .{});
672 }687 }
673688
674 if (self.zig_bss_section_index == null) {689 if (self.zig_bss_section_index == null) {
675 self.zig_bss_section_index = try self.allocateAllocSection(.{690 self.zig_bss_section_index = try self.addSection(.{
676 .name = ".zig.bss",691 .name = ".bss.zig",
677 .phdr_index = self.phdr_zig_load_zerofill_index.?,
678 .alignment = ptr_size,
679 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
680 .type = elf.SHT_NOBITS,692 .type = elf.SHT_NOBITS,
693 .addralign = ptr_size,
694 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
695 .offset = 0,
681 });696 });
697 const shdr = &self.shdrs.items[self.zig_bss_section_index.?];
698 if (self.phdr_zig_load_zerofill_index) |phndx| {
699 const phdr = self.phdrs.items[phndx];
700 shdr.sh_addr = phdr.p_vaddr;
701 shdr.sh_size = phdr.p_memsz;
702 try self.phdr_to_shdr_table.putNoClobber(gpa, self.zig_bss_section_index.?, phndx);
703 } else {
704 try zig_object.addSectionSymbol(self.zig_bss_section_index.?, self);
705 shdr.sh_size = 1024;
706 }
682 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_bss_section_index.?, .{});707 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_bss_section_index.?, .{});
683 }708 }
684709
685 const zig_object = self.zigObjectPtr().?;
686 if (zig_object.dwarf) |*dw| {710 if (zig_object.dwarf) |*dw| {
687 if (self.debug_str_section_index == null) {711 if (self.debug_str_section_index == null) {
688 assert(dw.strtab.buffer.items.len == 0);712 assert(dw.strtab.buffer.items.len == 0);
689 try dw.strtab.buffer.append(gpa, 0);713 try dw.strtab.buffer.append(gpa, 0);
690 self.debug_str_section_index = try self.allocateNonAllocSection(.{714 self.debug_str_section_index = try self.addSection(.{
691 .name = ".debug_str",715 .name = ".debug_str",
692 .size = @intCast(dw.strtab.buffer.items.len),
693 .flags = elf.SHF_MERGE | elf.SHF_STRINGS,716 .flags = elf.SHF_MERGE | elf.SHF_STRINGS,
694 .entsize = 1,717 .entsize = 1,
718 .type = elf.SHT_PROGBITS,
719 .addralign = 1,
720 .offset = std.math.maxInt(u64),
695 });721 });
722 const shdr = &self.shdrs.items[self.debug_str_section_index.?];
723 const size = @as(u64, @intCast(dw.strtab.buffer.items.len));
724 const off = self.findFreeSpace(size, 1);
725 shdr.sh_offset = off;
726 shdr.sh_size = size;
696 zig_object.debug_strtab_dirty = true;727 zig_object.debug_strtab_dirty = true;
697 }728 }
698729
699 if (self.debug_info_section_index == null) {730 if (self.debug_info_section_index == null) {
700 self.debug_info_section_index = try self.allocateNonAllocSection(.{731 self.debug_info_section_index = try self.addSection(.{
701 .name = ".debug_info",732 .name = ".debug_info",
702 .size = 200,733 .type = elf.SHT_PROGBITS,
703 .alignment = 1,734 .addralign = 1,
735 .offset = std.math.maxInt(u64),
704 });736 });
737 const shdr = &self.shdrs.items[self.debug_info_section_index.?];
738 const size: u64 = 200;
739 const off = self.findFreeSpace(size, 1);
740 shdr.sh_offset = off;
741 shdr.sh_size = size;
705 zig_object.debug_info_header_dirty = true;742 zig_object.debug_info_header_dirty = true;
706 }743 }
707744
708 if (self.debug_abbrev_section_index == null) {745 if (self.debug_abbrev_section_index == null) {
709 self.debug_abbrev_section_index = try self.allocateNonAllocSection(.{746 self.debug_abbrev_section_index = try self.addSection(.{
710 .name = ".debug_abbrev",747 .name = ".debug_abbrev",
711 .size = 128,748 .type = elf.SHT_PROGBITS,
712 .alignment = 1,749 .addralign = 1,
750 .offset = std.math.maxInt(u64),
713 });751 });
752 const shdr = &self.shdrs.items[self.debug_abbrev_section_index.?];
753 const size: u64 = 128;
754 const off = self.findFreeSpace(size, 1);
755 shdr.sh_offset = off;
756 shdr.sh_size = size;
714 zig_object.debug_abbrev_section_dirty = true;757 zig_object.debug_abbrev_section_dirty = true;
715 }758 }
716759
717 if (self.debug_aranges_section_index == null) {760 if (self.debug_aranges_section_index == null) {
718 self.debug_aranges_section_index = try self.allocateNonAllocSection(.{761 self.debug_aranges_section_index = try self.addSection(.{
719 .name = ".debug_aranges",762 .name = ".debug_aranges",
720 .size = 160,763 .type = elf.SHT_PROGBITS,
721 .alignment = 16,764 .addralign = 16,
765 .offset = std.math.maxInt(u64),
722 });766 });
767 const shdr = &self.shdrs.items[self.debug_aranges_section_index.?];
768 const size: u64 = 160;
769 const off = self.findFreeSpace(size, 16);
770 shdr.sh_offset = off;
771 shdr.sh_size = size;
723 zig_object.debug_aranges_section_dirty = true;772 zig_object.debug_aranges_section_dirty = true;
724 }773 }
725774
726 if (self.debug_line_section_index == null) {775 if (self.debug_line_section_index == null) {
727 self.debug_line_section_index = try self.allocateNonAllocSection(.{776 self.debug_line_section_index = try self.addSection(.{
728 .name = ".debug_line",777 .name = ".debug_line",
729 .size = 250,778 .type = elf.SHT_PROGBITS,
730 .alignment = 1,779 .addralign = 1,
780 .offset = std.math.maxInt(u64),
731 });781 });
782 const shdr = &self.shdrs.items[self.debug_line_section_index.?];
783 const size: u64 = 250;
784 const off = self.findFreeSpace(size, 1);
785 shdr.sh_offset = off;
786 shdr.sh_size = size;
732 zig_object.debug_line_header_dirty = true;787 zig_object.debug_line_header_dirty = true;
733 }788 }
734 }789 }
...@@ -736,18 +791,18 @@ pub fn initMetadata(self: *Elf) !void {...@@ -736,18 +791,18 @@ pub fn initMetadata(self: *Elf) !void {
736791
737pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void {792pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void {
738 const shdr = &self.shdrs.items[shdr_index];793 const shdr = &self.shdrs.items[shdr_index];
739 const phdr_index = self.phdr_to_shdr_table.get(shdr_index).?;794 const maybe_phdr = if (self.phdr_to_shdr_table.get(shdr_index)) |phndx| &self.phdrs.items[phndx] else null;
740 const phdr = &self.phdrs.items[phdr_index];
741 const is_zerofill = shdr.sh_type == elf.SHT_NOBITS;795 const is_zerofill = shdr.sh_type == elf.SHT_NOBITS;
742796
743 if (needed_size > self.allocatedSize(shdr.sh_offset) and !is_zerofill) {797 if (needed_size > self.allocatedSize(shdr.sh_offset) and !is_zerofill) {
744 const existing_size = shdr.sh_size;798 const existing_size = shdr.sh_size;
745 shdr.sh_size = 0;799 shdr.sh_size = 0;
746 // Must move the entire section.800 // Must move the entire section.
747 const new_offset = self.findFreeSpace(needed_size, self.page_size);801 const alignment = if (maybe_phdr) |phdr| phdr.p_align else shdr.sh_addralign;
802 const new_offset = self.findFreeSpace(needed_size, alignment);
748803
749 log.debug("new '{s}' file offset 0x{x} to 0x{x}", .{804 log.debug("new '{s}' file offset 0x{x} to 0x{x}", .{
750 self.shstrtab.getAssumeExists(shdr.sh_name),805 self.getShString(shdr.sh_name),
751 new_offset,806 new_offset,
752 new_offset + existing_size,807 new_offset + existing_size,
753 });808 });
...@@ -757,25 +812,27 @@ pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void {...@@ -757,25 +812,27 @@ pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void {
757 if (amt != existing_size) return error.InputOutput;812 if (amt != existing_size) return error.InputOutput;
758813
759 shdr.sh_offset = new_offset;814 shdr.sh_offset = new_offset;
760 phdr.p_offset = new_offset;815 if (maybe_phdr) |phdr| phdr.p_offset = new_offset;
761 }816 }
762817
763 shdr.sh_size = needed_size;818 shdr.sh_size = needed_size;
764 if (!is_zerofill) {819 if (!is_zerofill) {
765 phdr.p_filesz = needed_size;820 if (maybe_phdr) |phdr| phdr.p_filesz = needed_size;
766 }821 }
767822
768 const mem_capacity = self.allocatedVirtualSize(phdr.p_vaddr);823 if (maybe_phdr) |phdr| {
769 if (needed_size > mem_capacity) {824 const mem_capacity = self.allocatedVirtualSize(phdr.p_vaddr);
770 var err = try self.addErrorWithNotes(2);825 if (needed_size > mem_capacity) {
771 try err.addMsg(self, "fatal linker error: cannot expand load segment phdr({d}) in virtual memory", .{826 var err = try self.addErrorWithNotes(2);
772 phdr_index,827 try err.addMsg(self, "fatal linker error: cannot expand load segment phdr({d}) in virtual memory", .{
773 });828 self.phdr_to_shdr_table.get(shdr_index).?,
774 try err.addNote(self, "TODO: emit relocations to memory locations in self-hosted backends", .{});829 });
775 try err.addNote(self, "as a workaround, try increasing pre-allocated virtual memory of each segment", .{});830 try err.addNote(self, "TODO: emit relocations to memory locations in self-hosted backends", .{});
776 }831 try err.addNote(self, "as a workaround, try increasing pre-allocated virtual memory of each segment", .{});
832 }
777833
778 phdr.p_memsz = needed_size;834 phdr.p_memsz = needed_size;
835 }
779836
780 self.markDirty(shdr_index);837 self.markDirty(shdr_index);
781}838}
...@@ -796,7 +853,7 @@ pub fn growNonAllocSection(...@@ -796,7 +853,7 @@ pub fn growNonAllocSection(
796 const new_offset = self.findFreeSpace(needed_size, min_alignment);853 const new_offset = self.findFreeSpace(needed_size, min_alignment);
797854
798 log.debug("new '{s}' file offset 0x{x} to 0x{x}", .{855 log.debug("new '{s}' file offset 0x{x} to 0x{x}", .{
799 self.shstrtab.getAssumeExists(shdr.sh_name),856 self.getShString(shdr.sh_name),
800 new_offset,857 new_offset,
801 new_offset + existing_size,858 new_offset + existing_size,
802 });859 });
...@@ -847,10 +904,6 @@ pub fn flush(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) link...@@ -847,10 +904,6 @@ pub fn flush(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) link
847 if (use_lld) {904 if (use_lld) {
848 return self.linkWithLLD(comp, prog_node);905 return self.linkWithLLD(comp, prog_node);
849 }906 }
850 if (self.base.options.output_mode == .Lib and self.isStatic()) {
851 // TODO writing static library files
852 return error.TODOImplementWritingLibFiles;
853 }
854 try self.flushModule(comp, prog_node);907 try self.flushModule(comp, prog_node);
855}908}
856909
...@@ -886,7 +939,12 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -886,7 +939,12 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
886 } else null;939 } else null;
887 const gc_sections = self.base.options.gc_sections orelse false;940 const gc_sections = self.base.options.gc_sections orelse false;
888941
889 if (self.base.options.output_mode == .Obj and self.zig_object_index == null) {942 if (self.isRelocatable() and self.zig_object_index == null) {
943 if (self.isStaticLib()) {
944 var err = try self.addErrorWithNotes(0);
945 try err.addMsg(self, "fatal linker error: emitting static libs unimplemented", .{});
946 return;
947 }
890 // TODO this will become -r route I guess. For now, just copy the object file.948 // TODO this will become -r route I guess. For now, just copy the object file.
891 assert(self.base.file == null); // TODO uncomment once we implement -r949 assert(self.base.file == null); // TODO uncomment once we implement -r
892 const the_object_path = blk: {950 const the_object_path = blk: {
...@@ -1159,6 +1217,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1159,6 +1217,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1159 Compilation.dump_argv(argv.items);1217 Compilation.dump_argv(argv.items);
1160 }1218 }
11611219
1220 if (self.zigObjectPtr()) |zig_object| try zig_object.flushModule(self);
1221
1162 // Here we will parse input positional and library files (if referenced).1222 // Here we will parse input positional and library files (if referenced).
1163 // This will roughly match in any linker backend we support.1223 // This will roughly match in any linker backend we support.
1164 var positionals = std.ArrayList(Compilation.LinkObject).init(arena);1224 var positionals = std.ArrayList(Compilation.LinkObject).init(arena);
...@@ -1226,6 +1286,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1226,6 +1286,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1226 try positionals.append(.{ .path = ssp.full_object_path });1286 try positionals.append(.{ .path = ssp.full_object_path });
1227 }1287 }
12281288
1289 if (self.isStaticLib()) return self.flushStaticLib(comp, positionals.items);
1290
1229 for (positionals.items) |obj| {1291 for (positionals.items) |obj| {
1230 var parse_ctx: ParseErrorCtx = .{ .detected_cpu_arch = undefined };1292 var parse_ctx: ParseErrorCtx = .{ .detected_cpu_arch = undefined };
1231 self.parsePositional(obj.path, obj.must_link, &parse_ctx) catch |err|1293 self.parsePositional(obj.path, obj.must_link, &parse_ctx) catch |err|
...@@ -1331,8 +1393,6 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1331,8 +1393,6 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1331 try self.handleAndReportParseError(obj.path, err, &parse_ctx);1393 try self.handleAndReportParseError(obj.path, err, &parse_ctx);
1332 }1394 }
13331395
1334 if (self.zigObjectPtr()) |zig_object| try zig_object.flushModule(self);
1335
1336 // Dedup shared objects1396 // Dedup shared objects
1337 {1397 {
1338 var seen_dsos = std.StringHashMap(void).init(gpa);1398 var seen_dsos = std.StringHashMap(void).init(gpa);
...@@ -1353,7 +1413,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1353,7 +1413,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
13531413
1354 // If we haven't already, create a linker-generated input file comprising of1414 // If we haven't already, create a linker-generated input file comprising of
1355 // linker-defined synthetic symbols only such as `_DYNAMIC`, etc.1415 // linker-defined synthetic symbols only such as `_DYNAMIC`, etc.
1356 if (self.linker_defined_index == null) {1416 if (self.linker_defined_index == null and !self.isRelocatable()) {
1357 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));1417 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
1358 self.files.set(index, .{ .linker_defined = .{ .index = index } });1418 self.files.set(index, .{ .linker_defined = .{ .index = index } });
1359 self.linker_defined_index = index;1419 self.linker_defined_index = index;
...@@ -1366,6 +1426,9 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1366,6 +1426,9 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1366 // symbol for potential resolution at load-time.1426 // symbol for potential resolution at load-time.
1367 self.resolveSymbols();1427 self.resolveSymbols();
1368 self.markEhFrameAtomsDead();1428 self.markEhFrameAtomsDead();
1429
1430 if (self.isObject()) return self.flushObject(comp);
1431
1369 try self.convertCommonSymbols();1432 try self.convertCommonSymbols();
1370 self.markImportsExports();1433 self.markImportsExports();
13711434
...@@ -1449,14 +1512,150 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1449,14 +1512,150 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1449 try self.writeAtoms();1512 try self.writeAtoms();
1450 try self.writeSyntheticSections();1513 try self.writeSyntheticSections();
14511514
1452 if (self.entry_index == null and self.base.options.effectiveOutputMode() == .Exe) {1515 if (self.entry_index == null and self.isExe()) {
1453 log.debug("flushing. no_entry_point_found = true", .{});1516 log.debug("flushing. no_entry_point_found = true", .{});
1454 self.error_flags.no_entry_point_found = true;1517 self.error_flags.no_entry_point_found = true;
1455 } else {1518 } else {
1456 log.debug("flushing. no_entry_point_found = false", .{});1519 log.debug("flushing. no_entry_point_found = false", .{});
1457 self.error_flags.no_entry_point_found = false;1520 self.error_flags.no_entry_point_found = false;
1458 try self.writeHeader();1521 try self.writeElfHeader();
1522 }
1523}
1524
1525pub fn flushStaticLib(
1526 self: *Elf,
1527 comp: *Compilation,
1528 positionals: []const Compilation.LinkObject,
1529) link.File.FlushError!void {
1530 _ = comp;
1531 if (positionals.len > 0) {
1532 var err = try self.addErrorWithNotes(1);
1533 try err.addMsg(self, "fatal linker error: too many input positionals", .{});
1534 try err.addNote(self, "TODO implement linking objects into an static library", .{});
1535 return;
1536 }
1537 const gpa = self.base.allocator;
1538
1539 // First, we flush relocatable object file generated with our backends.
1540 if (self.zigObjectPtr()) |zig_object| {
1541 zig_object.resolveSymbols(self);
1542 zig_object.claimUnresolvedObject(self);
1543
1544 try self.initSymtab();
1545 try self.initShStrtab();
1546 try self.sortShdrs();
1547 zig_object.updateRelaSectionSizes(self);
1548 try self.updateSymtabSize();
1549 self.updateShStrtabSize();
1550
1551 try self.allocateNonAllocSections();
1552
1553 try self.writeShdrTable();
1554 try zig_object.writeRelaSections(self);
1555 try self.writeSymtab();
1556 try self.writeShStrtab();
1557 try self.writeElfHeader();
1558 }
1559
1560 // TODO parse positionals that we want to make part of the archive
1561
1562 // TODO update ar symtab from parsed positionals
1563
1564 var ar_symtab: Archive.ArSymtab = .{};
1565 defer ar_symtab.deinit(gpa);
1566
1567 if (self.zigObjectPtr()) |zig_object| {
1568 try zig_object.updateArSymtab(&ar_symtab, self);
1569 }
1570
1571 ar_symtab.sort();
1572
1573 // Save object paths in filenames strtab.
1574 var ar_strtab: Archive.ArStrtab = .{};
1575 defer ar_strtab.deinit(gpa);
1576
1577 if (self.zigObjectPtr()) |zig_object| {
1578 try zig_object.updateArStrtab(gpa, &ar_strtab);
1579 zig_object.updateArSize(self);
1580 }
1581
1582 // Update file offsets of contributing objects.
1583 const total_size: usize = blk: {
1584 var pos: usize = Archive.SARMAG;
1585 pos += @sizeOf(Archive.ar_hdr) + ar_symtab.size(.p64);
1586
1587 if (ar_strtab.size() > 0) {
1588 pos = mem.alignForward(usize, pos, 2);
1589 pos += @sizeOf(Archive.ar_hdr) + ar_strtab.size();
1590 }
1591
1592 if (self.zigObjectPtr()) |zig_object| {
1593 pos = mem.alignForward(usize, pos, 2);
1594 zig_object.output_ar_state.file_off = pos;
1595 pos += @sizeOf(Archive.ar_hdr) + (math.cast(usize, zig_object.output_ar_state.size) orelse return error.Overflow);
1596 }
1597
1598 break :blk pos;
1599 };
1600
1601 if (build_options.enable_logging) {
1602 state_log.debug("ar_symtab\n{}\n", .{ar_symtab.fmt(self)});
1603 state_log.debug("ar_strtab\n{}\n", .{ar_strtab});
1604 }
1605
1606 var buffer = std.ArrayList(u8).init(gpa);
1607 defer buffer.deinit();
1608 try buffer.ensureTotalCapacityPrecise(total_size);
1609
1610 // Write magic
1611 try buffer.writer().writeAll(Archive.ARMAG);
1612
1613 // Write symtab
1614 try ar_symtab.write(.p64, self, buffer.writer());
1615
1616 // Write strtab
1617 if (ar_strtab.size() > 0) {
1618 if (!mem.isAligned(buffer.items.len, 2)) try buffer.writer().writeByte(0);
1619 try ar_strtab.write(buffer.writer());
1620 }
1621
1622 // Write object files
1623 if (self.zigObjectPtr()) |zig_object| {
1624 if (!mem.isAligned(buffer.items.len, 2)) try buffer.writer().writeByte(0);
1625 try zig_object.writeAr(self, buffer.writer());
1626 }
1627
1628 assert(buffer.items.len == total_size);
1629
1630 try self.base.file.?.setEndPos(total_size);
1631 try self.base.file.?.pwriteAll(buffer.items, 0);
1632}
1633
1634pub fn flushObject(self: *Elf, comp: *Compilation) link.File.FlushError!void {
1635 _ = comp;
1636
1637 if (self.objects.items.len > 0) {
1638 var err = try self.addErrorWithNotes(1);
1639 try err.addMsg(self, "fatal linker error: too many input positionals", .{});
1640 try err.addNote(self, "TODO implement '-r' option", .{});
1641 return;
1642 }
1643
1644 self.claimUnresolvedObject();
1645
1646 try self.initSections();
1647 try self.sortShdrs();
1648 try self.updateSectionSizes();
1649
1650 try self.allocateNonAllocSections();
1651
1652 if (build_options.enable_logging) {
1653 state_log.debug("{}", .{self.dumpState()});
1459 }1654 }
1655
1656 try self.writeShdrTable();
1657 try self.writeSyntheticSections();
1658 try self.writeElfHeader();
1460}1659}
14611660
1462const ParseError = error{1661const ParseError = error{
...@@ -1696,7 +1895,7 @@ fn accessLibPath(...@@ -1696,7 +1895,7 @@ fn accessLibPath(
1696/// 6. Re-run symbol resolution on pruned objects and shared objects sets.1895/// 6. Re-run symbol resolution on pruned objects and shared objects sets.
1697fn resolveSymbols(self: *Elf) void {1896fn resolveSymbols(self: *Elf) void {
1698 // Resolve symbols in the ZigObject. For now, we assume that it's always live.1897 // Resolve symbols in the ZigObject. For now, we assume that it's always live.
1699 if (self.zigObjectPtr()) |zig_object| zig_object.resolveSymbols(self);1898 if (self.zigObjectPtr()) |zig_object| zig_object.asFile().resolveSymbols(self);
1700 // Resolve symbols on the set of all objects and shared objects (even if some are unneeded).1899 // Resolve symbols on the set of all objects and shared objects (even if some are unneeded).
1701 for (self.objects.items) |index| self.file(index).?.resolveSymbols(self);1900 for (self.objects.items) |index| self.file(index).?.resolveSymbols(self);
1702 for (self.shared_objects.items) |index| self.file(index).?.resolveSymbols(self);1901 for (self.shared_objects.items) |index| self.file(index).?.resolveSymbols(self);
...@@ -1705,7 +1904,7 @@ fn resolveSymbols(self: *Elf) void {...@@ -1705,7 +1904,7 @@ fn resolveSymbols(self: *Elf) void {
1705 self.markLive();1904 self.markLive();
17061905
1707 // Reset state of all globals after marking live objects.1906 // Reset state of all globals after marking live objects.
1708 if (self.zigObjectPtr()) |zig_object| zig_object.resetGlobals(self);1907 if (self.zigObjectPtr()) |zig_object| zig_object.asFile().resetGlobals(self);
1709 for (self.objects.items) |index| self.file(index).?.resetGlobals(self);1908 for (self.objects.items) |index| self.file(index).?.resetGlobals(self);
1710 for (self.shared_objects.items) |index| self.file(index).?.resetGlobals(self);1909 for (self.shared_objects.items) |index| self.file(index).?.resetGlobals(self);
17111910
...@@ -1767,7 +1966,7 @@ fn resolveSymbols(self: *Elf) void {...@@ -1767,7 +1966,7 @@ fn resolveSymbols(self: *Elf) void {
1767/// This routine will prune unneeded objects extracted from archives and1966/// This routine will prune unneeded objects extracted from archives and
1768/// unneeded shared objects.1967/// unneeded shared objects.
1769fn markLive(self: *Elf) void {1968fn markLive(self: *Elf) void {
1770 if (self.zigObjectPtr()) |zig_object| zig_object.markLive(self);1969 if (self.zigObjectPtr()) |zig_object| zig_object.asFile().markLive(self);
1771 for (self.objects.items) |index| {1970 for (self.objects.items) |index| {
1772 const file_ptr = self.file(index).?;1971 const file_ptr = self.file(index).?;
1773 if (file_ptr.isAlive()) file_ptr.markLive(self);1972 if (file_ptr.isAlive()) file_ptr.markLive(self);
...@@ -1845,6 +2044,12 @@ fn claimUnresolved(self: *Elf) void {...@@ -1845,6 +2044,12 @@ fn claimUnresolved(self: *Elf) void {
1845 }2044 }
1846}2045}
18472046
2047fn claimUnresolvedObject(self: *Elf) void {
2048 if (self.zigObjectPtr()) |zig_object| {
2049 zig_object.claimUnresolvedObject(self);
2050 }
2051}
2052
1848/// In scanRelocs we will go over all live atoms and scan their relocs.2053/// In scanRelocs we will go over all live atoms and scan their relocs.
1849/// This will help us work out what synthetics to emit, GOT indirection, etc.2054/// This will help us work out what synthetics to emit, GOT indirection, etc.
1850/// This is also the point where we will report undefined symbols for any2055/// This is also the point where we will report undefined symbols for any
...@@ -1873,7 +2078,7 @@ fn scanRelocs(self: *Elf) !void {...@@ -1873,7 +2078,7 @@ fn scanRelocs(self: *Elf) !void {
18732078
1874 for (self.symbols.items, 0..) |*sym, i| {2079 for (self.symbols.items, 0..) |*sym, i| {
1875 const index = @as(u32, @intCast(i));2080 const index = @as(u32, @intCast(i));
1876 if (!sym.isLocal() and !sym.flags.has_dynamic) {2081 if (!sym.isLocal(self) and !sym.flags.has_dynamic) {
1877 log.debug("'{s}' is non-local", .{sym.name(self)});2082 log.debug("'{s}' is non-local", .{sym.name(self)});
1878 try self.dynsym.addSymbol(index, self);2083 try self.dynsym.addSymbol(index, self);
1879 }2084 }
...@@ -2704,7 +2909,7 @@ fn writePhdrTable(self: *Elf) !void {...@@ -2704,7 +2909,7 @@ fn writePhdrTable(self: *Elf) !void {
2704 }2909 }
2705}2910}
27062911
2707fn writeHeader(self: *Elf) !void {2912fn writeElfHeader(self: *Elf) !void {
2708 var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 = undefined;2913 var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 = undefined;
27092914
2710 var index: usize = 0;2915 var index: usize = 0;
...@@ -2735,7 +2940,7 @@ fn writeHeader(self: *Elf) !void {...@@ -2735,7 +2940,7 @@ fn writeHeader(self: *Elf) !void {
27352940
2736 assert(index == 16);2941 assert(index == 16);
27372942
2738 const elf_type: elf.ET = switch (self.base.options.effectiveOutputMode()) {2943 const elf_type: elf.ET = switch (self.base.options.output_mode) {
2739 .Exe => if (self.base.options.pie) .DYN else .EXEC,2944 .Exe => if (self.base.options.pie) .DYN else .EXEC,
2740 .Obj => .REL,2945 .Obj => .REL,
2741 .Lib => switch (self.base.options.link_mode) {2946 .Lib => switch (self.base.options.link_mode) {
...@@ -2755,7 +2960,7 @@ fn writeHeader(self: *Elf) !void {...@@ -2755,7 +2960,7 @@ fn writeHeader(self: *Elf) !void {
2755 index += 4;2960 index += 4;
27562961
2757 const e_entry = if (self.entry_index) |entry_index| self.symbol(entry_index).value else 0;2962 const e_entry = if (self.entry_index) |entry_index| self.symbol(entry_index).value else 0;
2758 const phdr_table_offset = self.phdrs.items[self.phdr_table_index.?].p_offset;2963 const phdr_table_offset = if (self.phdr_table_index) |phndx| self.phdrs.items[phndx].p_offset else 0;
2759 switch (self.ptr_width) {2964 switch (self.ptr_width) {
2760 .p32 => {2965 .p32 => {
2761 mem.writeInt(u32, hdr_buf[index..][0..4], @as(u32, @intCast(e_entry)), endian);2966 mem.writeInt(u32, hdr_buf[index..][0..4], @as(u32, @intCast(e_entry)), endian);
...@@ -3054,10 +3259,6 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {...@@ -3054,10 +3259,6 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {
3054}3259}
30553260
3056fn initSections(self: *Elf) !void {3261fn initSections(self: *Elf) !void {
3057 const small_ptr = switch (self.ptr_width) {
3058 .p32 => true,
3059 .p64 => false,
3060 };
3061 const ptr_size = self.ptrWidthBytes();3262 const ptr_size = self.ptrWidthBytes();
30623263
3063 for (self.objects.items) |index| {3264 for (self.objects.items) |index| {
...@@ -3247,6 +3448,15 @@ fn initSections(self: *Elf) !void {...@@ -3247,6 +3448,15 @@ fn initSections(self: *Elf) !void {
3247 }3448 }
3248 }3449 }
32493450
3451 try self.initSymtab();
3452 try self.initShStrtab();
3453}
3454
3455fn initSymtab(self: *Elf) !void {
3456 const small_ptr = switch (self.ptr_width) {
3457 .p32 => true,
3458 .p64 => false,
3459 };
3250 if (self.symtab_section_index == null) {3460 if (self.symtab_section_index == null) {
3251 self.symtab_section_index = try self.addSection(.{3461 self.symtab_section_index = try self.addSection(.{
3252 .name = ".symtab",3462 .name = ".symtab",
...@@ -3265,6 +3475,9 @@ fn initSections(self: *Elf) !void {...@@ -3265,6 +3475,9 @@ fn initSections(self: *Elf) !void {
3265 .offset = std.math.maxInt(u64),3475 .offset = std.math.maxInt(u64),
3266 });3476 });
3267 }3477 }
3478}
3479
3480fn initShStrtab(self: *Elf) !void {
3268 if (self.shstrtab_section_index == null) {3481 if (self.shstrtab_section_index == null) {
3269 self.shstrtab_section_index = try self.addSection(.{3482 self.shstrtab_section_index = try self.addSection(.{
3270 .name = ".shstrtab",3483 .name = ".shstrtab",
...@@ -3358,7 +3571,7 @@ fn sortInitFini(self: *Elf) !void {...@@ -3358,7 +3571,7 @@ fn sortInitFini(self: *Elf) !void {
3358 elf.SHT_FINI_ARRAY,3571 elf.SHT_FINI_ARRAY,
3359 => is_init_fini = true,3572 => is_init_fini = true,
3360 else => {3573 else => {
3361 const name = self.shstrtab.getAssumeExists(shdr.sh_name);3574 const name = self.getShString(shdr.sh_name);
3362 is_ctor_dtor = mem.indexOf(u8, name, ".ctors") != null or mem.indexOf(u8, name, ".dtors") != null;3575 is_ctor_dtor = mem.indexOf(u8, name, ".ctors") != null or mem.indexOf(u8, name, ".dtors") != null;
3363 },3576 },
3364 }3577 }
...@@ -3520,7 +3733,7 @@ fn sortPhdrs(self: *Elf) error{OutOfMemory}!void {...@@ -3520,7 +3733,7 @@ fn sortPhdrs(self: *Elf) error{OutOfMemory}!void {
35203733
3521fn shdrRank(self: *Elf, shndx: u16) u8 {3734fn shdrRank(self: *Elf, shndx: u16) u8 {
3522 const shdr = self.shdrs.items[shndx];3735 const shdr = self.shdrs.items[shndx];
3523 const name = self.shstrtab.getAssumeExists(shdr.sh_name);3736 const name = self.getShString(shdr.sh_name);
3524 const flags = shdr.sh_flags;3737 const flags = shdr.sh_flags;
35253738
3526 switch (shdr.sh_type) {3739 switch (shdr.sh_type) {
...@@ -3620,9 +3833,12 @@ fn sortShdrs(self: *Elf) !void {...@@ -3620,9 +3833,12 @@ fn sortShdrs(self: *Elf) !void {
3620 &self.versym_section_index,3833 &self.versym_section_index,
3621 &self.verneed_section_index,3834 &self.verneed_section_index,
3622 &self.zig_text_section_index,3835 &self.zig_text_section_index,
3836 &self.zig_text_rela_section_index,
3623 &self.zig_got_section_index,3837 &self.zig_got_section_index,
3624 &self.zig_rodata_section_index,3838 &self.zig_data_rel_ro_section_index,
3839 &self.zig_data_rel_ro_rela_section_index,
3625 &self.zig_data_section_index,3840 &self.zig_data_section_index,
3841 &self.zig_data_rela_section_index,
3626 &self.zig_bss_section_index,3842 &self.zig_bss_section_index,
3627 &self.debug_str_section_index,3843 &self.debug_str_section_index,
3628 &self.debug_info_section_index,3844 &self.debug_info_section_index,
...@@ -3681,6 +3897,31 @@ fn sortShdrs(self: *Elf) !void {...@@ -3681,6 +3897,31 @@ fn sortShdrs(self: *Elf) !void {
3681 shdr.sh_info = self.plt_section_index.?;3897 shdr.sh_info = self.plt_section_index.?;
3682 }3898 }
36833899
3900 for (&[_]?u16{
3901 self.zig_text_rela_section_index,
3902 self.zig_data_rel_ro_rela_section_index,
3903 self.zig_data_rela_section_index,
3904 }) |maybe_index| {
3905 const index = maybe_index orelse continue;
3906 const shdr = &self.shdrs.items[index];
3907 shdr.sh_link = self.symtab_section_index.?;
3908 shdr.sh_info = backlinks[shdr.sh_info];
3909 }
3910
3911 {
3912 var last_atom_and_free_list_table = try self.last_atom_and_free_list_table.clone(gpa);
3913 defer last_atom_and_free_list_table.deinit(gpa);
3914
3915 self.last_atom_and_free_list_table.clearRetainingCapacity();
3916
3917 var it = last_atom_and_free_list_table.iterator();
3918 while (it.next()) |entry| {
3919 const shndx = entry.key_ptr.*;
3920 const meta = entry.value_ptr.*;
3921 self.last_atom_and_free_list_table.putAssumeCapacityNoClobber(backlinks[shndx], meta);
3922 }
3923 }
3924
3684 {3925 {
3685 var phdr_to_shdr_table = try self.phdr_to_shdr_table.clone(gpa);3926 var phdr_to_shdr_table = try self.phdr_to_shdr_table.clone(gpa);
3686 defer phdr_to_shdr_table.deinit(gpa);3927 defer phdr_to_shdr_table.deinit(gpa);
...@@ -3698,23 +3939,19 @@ fn sortShdrs(self: *Elf) !void {...@@ -3698,23 +3939,19 @@ fn sortShdrs(self: *Elf) !void {
3698 if (self.zigObjectPtr()) |zig_object| {3939 if (self.zigObjectPtr()) |zig_object| {
3699 for (zig_object.atoms.items) |atom_index| {3940 for (zig_object.atoms.items) |atom_index| {
3700 const atom_ptr = self.atom(atom_index) orelse continue;3941 const atom_ptr = self.atom(atom_index) orelse continue;
3701 if (!atom_ptr.flags.alive) continue;3942 atom_ptr.output_section_index = backlinks[atom_ptr.output_section_index];
3702 const out_shndx = atom_ptr.outputShndx() orelse continue;
3703 atom_ptr.output_section_index = backlinks[out_shndx];
3704 }3943 }
37053944
3706 for (zig_object.locals()) |local_index| {3945 for (zig_object.locals()) |local_index| {
3707 const local = self.symbol(local_index);3946 const local = self.symbol(local_index);
3708 const atom_ptr = local.atom(self) orelse continue;3947 local.output_section_index = backlinks[local.output_section_index];
3709 if (!atom_ptr.flags.alive) continue;
3710 const out_shndx = local.outputShndx() orelse continue;
3711 local.output_section_index = backlinks[out_shndx];
3712 }3948 }
37133949
3714 for (zig_object.globals()) |global_index| {3950 for (zig_object.globals()) |global_index| {
3715 const global = self.symbol(global_index);3951 const global = self.symbol(global_index);
3716 const atom_ptr = global.atom(self) orelse continue;3952 const atom_ptr = global.atom(self) orelse continue;
3717 if (!atom_ptr.flags.alive) continue;3953 if (!atom_ptr.flags.alive) continue;
3954 // TODO claim unresolved for objects
3718 if (global.file(self).?.index() != zig_object.index) continue;3955 if (global.file(self).?.index() != zig_object.index) continue;
3719 const out_shndx = global.outputShndx() orelse continue;3956 const out_shndx = global.outputShndx() orelse continue;
3720 global.output_section_index = backlinks[out_shndx];3957 global.output_section_index = backlinks[out_shndx];
...@@ -3737,6 +3974,10 @@ fn updateSectionSizes(self: *Elf) !void {...@@ -3737,6 +3974,10 @@ fn updateSectionSizes(self: *Elf) !void {
3737 }3974 }
3738 }3975 }
37393976
3977 if (self.zigObjectPtr()) |zig_object| {
3978 zig_object.updateRelaSectionSizes(self);
3979 }
3980
3740 if (self.eh_frame_section_index) |index| {3981 if (self.eh_frame_section_index) |index| {
3741 self.shdrs.items[index].sh_size = try eh_frame.calcEhFrameSize(self);3982 self.shdrs.items[index].sh_size = try eh_frame.calcEhFrameSize(self);
3742 }3983 }
...@@ -3801,7 +4042,7 @@ fn updateSectionSizes(self: *Elf) !void {...@@ -3801,7 +4042,7 @@ fn updateSectionSizes(self: *Elf) !void {
3801 }4042 }
38024043
3803 if (self.dynstrtab_section_index) |index| {4044 if (self.dynstrtab_section_index) |index| {
3804 self.shdrs.items[index].sh_size = self.dynstrtab.buffer.items.len;4045 self.shdrs.items[index].sh_size = self.dynstrtab.items.len;
3805 }4046 }
38064047
3807 if (self.versym_section_index) |index| {4048 if (self.versym_section_index) |index| {
...@@ -3812,30 +4053,13 @@ fn updateSectionSizes(self: *Elf) !void {...@@ -3812,30 +4053,13 @@ fn updateSectionSizes(self: *Elf) !void {
3812 self.shdrs.items[index].sh_size = self.verneed.size();4053 self.shdrs.items[index].sh_size = self.verneed.size();
3813 }4054 }
38144055
3815 if (self.symtab_section_index != null) {4056 try self.updateSymtabSize();
3816 try self.updateSymtabSize();4057 self.updateShStrtabSize();
3817 }4058}
3818
3819 if (self.strtab_section_index) |index| {
3820 // TODO I don't really this here but we need it to add symbol names from GOT and other synthetic
3821 // sections into .strtab for easier debugging.
3822 if (self.zig_got_section_index) |_| {
3823 try self.zig_got.updateStrtab(self);
3824 }
3825 if (self.got_section_index) |_| {
3826 try self.got.updateStrtab(self);
3827 }
3828 if (self.plt_section_index) |_| {
3829 try self.plt.updateStrtab(self);
3830 }
3831 if (self.plt_got_section_index) |_| {
3832 try self.plt_got.updateStrtab(self);
3833 }
3834 self.shdrs.items[index].sh_size = self.strtab.buffer.items.len;
3835 }
38364059
4060fn updateShStrtabSize(self: *Elf) void {
3837 if (self.shstrtab_section_index) |index| {4061 if (self.shstrtab_section_index) |index| {
3838 self.shdrs.items[index].sh_size = self.shstrtab.buffer.items.len;4062 self.shdrs.items[index].sh_size = self.shstrtab.items.len;
3839 }4063 }
3840}4064}
38414065
...@@ -4074,7 +4298,7 @@ fn allocateNonAllocSections(self: *Elf) !void {...@@ -4074,7 +4298,7 @@ fn allocateNonAllocSections(self: *Elf) !void {
40744298
4075 if (self.isDebugSection(@intCast(shndx))) {4299 if (self.isDebugSection(@intCast(shndx))) {
4076 log.debug("moving {s} from 0x{x} to 0x{x}", .{4300 log.debug("moving {s} from 0x{x} to 0x{x}", .{
4077 self.shstrtab.getAssumeExists(shdr.sh_name),4301 self.getShString(shdr.sh_name),
4078 shdr.sh_offset,4302 shdr.sh_offset,
4079 new_offset,4303 new_offset,
4080 });4304 });
...@@ -4187,7 +4411,7 @@ fn writeAtoms(self: *Elf) !void {...@@ -4187,7 +4411,7 @@ fn writeAtoms(self: *Elf) !void {
41874411
4188 const atom_list = self.output_sections.get(@intCast(shndx)) orelse continue;4412 const atom_list = self.output_sections.get(@intCast(shndx)) orelse continue;
41894413
4190 log.debug("writing atoms in '{s}' section", .{self.shstrtab.getAssumeExists(shdr.sh_name)});4414 log.debug("writing atoms in '{s}' section", .{self.getShString(shdr.sh_name)});
41914415
4192 // TODO really, really handle debug section separately4416 // TODO really, really handle debug section separately
4193 const base_offset = if (self.isDebugSection(@intCast(shndx))) blk: {4417 const base_offset = if (self.isDebugSection(@intCast(shndx))) blk: {
...@@ -4256,65 +4480,70 @@ fn updateSymtabSize(self: *Elf) !void {...@@ -4256,65 +4480,70 @@ fn updateSymtabSize(self: *Elf) !void {
4256 var sizes = SymtabSize{};4480 var sizes = SymtabSize{};
42574481
4258 if (self.zigObjectPtr()) |zig_object| {4482 if (self.zigObjectPtr()) |zig_object| {
4259 zig_object.updateSymtabSize(self);4483 zig_object.asFile().updateSymtabSize(self);
4260 sizes.nlocals += zig_object.output_symtab_size.nlocals;4484 sizes.add(zig_object.output_symtab_size);
4261 sizes.nglobals += zig_object.output_symtab_size.nglobals;
4262 }4485 }
42634486
4264 for (self.objects.items) |index| {4487 for (self.objects.items) |index| {
4265 const object = self.file(index).?.object;4488 const file_ptr = self.file(index).?;
4266 object.updateSymtabSize(self);4489 file_ptr.updateSymtabSize(self);
4267 sizes.nlocals += object.output_symtab_size.nlocals;4490 sizes.add(file_ptr.object.output_symtab_size);
4268 sizes.nglobals += object.output_symtab_size.nglobals;
4269 }4491 }
42704492
4271 for (self.shared_objects.items) |index| {4493 for (self.shared_objects.items) |index| {
4272 const shared_object = self.file(index).?.shared_object;4494 const file_ptr = self.file(index).?;
4273 shared_object.updateSymtabSize(self);4495 file_ptr.updateSymtabSize(self);
4274 sizes.nglobals += shared_object.output_symtab_size.nglobals;4496 sizes.add(file_ptr.shared_object.output_symtab_size);
4275 }4497 }
42764498
4277 if (self.zig_got_section_index) |_| {4499 if (self.zig_got_section_index) |_| {
4278 self.zig_got.updateSymtabSize(self);4500 self.zig_got.updateSymtabSize(self);
4279 sizes.nlocals += self.zig_got.output_symtab_size.nlocals;4501 sizes.add(self.zig_got.output_symtab_size);
4280 }4502 }
42814503
4282 if (self.got_section_index) |_| {4504 if (self.got_section_index) |_| {
4283 self.got.updateSymtabSize(self);4505 self.got.updateSymtabSize(self);
4284 sizes.nlocals += self.got.output_symtab_size.nlocals;4506 sizes.add(self.got.output_symtab_size);
4285 }4507 }
42864508
4287 if (self.plt_section_index) |_| {4509 if (self.plt_section_index) |_| {
4288 self.plt.updateSymtabSize(self);4510 self.plt.updateSymtabSize(self);
4289 sizes.nlocals += self.plt.output_symtab_size.nlocals;4511 sizes.add(self.plt.output_symtab_size);
4290 }4512 }
42914513
4292 if (self.plt_got_section_index) |_| {4514 if (self.plt_got_section_index) |_| {
4293 self.plt_got.updateSymtabSize(self);4515 self.plt_got.updateSymtabSize(self);
4294 sizes.nlocals += self.plt_got.output_symtab_size.nlocals;4516 sizes.add(self.plt_got.output_symtab_size);
4295 }4517 }
42964518
4297 if (self.linker_defined_index) |index| {4519 if (self.linker_defined_index) |index| {
4298 const linker_defined = self.file(index).?.linker_defined;4520 const file_ptr = self.file(index).?;
4299 linker_defined.updateSymtabSize(self);4521 file_ptr.updateSymtabSize(self);
4300 sizes.nlocals += linker_defined.output_symtab_size.nlocals;4522 sizes.add(file_ptr.linker_defined.output_symtab_size);
4301 }4523 }
43024524
4303 const shdr = &self.shdrs.items[self.symtab_section_index.?];4525 const symtab_shdr = &self.shdrs.items[self.symtab_section_index.?];
4304 shdr.sh_info = sizes.nlocals + 1;4526 symtab_shdr.sh_info = sizes.nlocals + 1;
4305 shdr.sh_link = self.strtab_section_index.?;4527 symtab_shdr.sh_link = self.strtab_section_index.?;
43064528
4307 const sym_size: u64 = switch (self.ptr_width) {4529 const sym_size: u64 = switch (self.ptr_width) {
4308 .p32 => @sizeOf(elf.Elf32_Sym),4530 .p32 => @sizeOf(elf.Elf32_Sym),
4309 .p64 => @sizeOf(elf.Elf64_Sym),4531 .p64 => @sizeOf(elf.Elf64_Sym),
4310 };4532 };
4311 const needed_size = (sizes.nlocals + sizes.nglobals + 1) * sym_size;4533 const needed_size = (sizes.nlocals + sizes.nglobals + 1) * sym_size;
4312 shdr.sh_size = needed_size;4534 symtab_shdr.sh_size = needed_size;
4535
4536 const strtab = &self.shdrs.items[self.strtab_section_index.?];
4537 strtab.sh_size = sizes.strsize + 1;
4313}4538}
43144539
4315fn writeSyntheticSections(self: *Elf) !void {4540fn writeSyntheticSections(self: *Elf) !void {
4316 const gpa = self.base.allocator;4541 const gpa = self.base.allocator;
43174542
4543 if (self.zigObjectPtr()) |zig_object| {
4544 try zig_object.writeRelaSections(self);
4545 }
4546
4318 if (self.interp_section_index) |shndx| {4547 if (self.interp_section_index) |shndx| {
4319 const shdr = self.shdrs.items[shndx];4548 const shdr = self.shdrs.items[shndx];
4320 const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;4549 const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;
...@@ -4370,7 +4599,7 @@ fn writeSyntheticSections(self: *Elf) !void {...@@ -4370,7 +4599,7 @@ fn writeSyntheticSections(self: *Elf) !void {
43704599
4371 if (self.dynstrtab_section_index) |shndx| {4600 if (self.dynstrtab_section_index) |shndx| {
4372 const shdr = self.shdrs.items[shndx];4601 const shdr = self.shdrs.items[shndx];
4373 try self.base.file.?.pwriteAll(self.dynstrtab.buffer.items, shdr.sh_offset);4602 try self.base.file.?.pwriteAll(self.dynstrtab.items, shdr.sh_offset);
4374 }4603 }
43754604
4376 if (self.eh_frame_section_index) |shndx| {4605 if (self.eh_frame_section_index) |shndx| {
...@@ -4438,94 +4667,97 @@ fn writeSyntheticSections(self: *Elf) !void {...@@ -4438,94 +4667,97 @@ fn writeSyntheticSections(self: *Elf) !void {
4438 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.rela_plt.items), shdr.sh_offset);4667 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.rela_plt.items), shdr.sh_offset);
4439 }4668 }
44404669
4441 if (self.shstrtab_section_index) |index| {4670 try self.writeSymtab();
4442 const shdr = self.shdrs.items[index];4671 try self.writeShStrtab();
4443 try self.base.file.?.pwriteAll(self.shstrtab.buffer.items, shdr.sh_offset);4672}
4444 }
44454673
4446 if (self.strtab_section_index) |index| {4674fn writeShStrtab(self: *Elf) !void {
4675 if (self.shstrtab_section_index) |index| {
4447 const shdr = self.shdrs.items[index];4676 const shdr = self.shdrs.items[index];
4448 try self.base.file.?.pwriteAll(self.strtab.buffer.items, shdr.sh_offset);4677 try self.base.file.?.pwriteAll(self.shstrtab.items, shdr.sh_offset);
4449 }
4450
4451 if (self.symtab_section_index) |_| {
4452 try self.writeSymtab();
4453 }4678 }
4454}4679}
44554680
4456fn writeSymtab(self: *Elf) !void {4681fn writeSymtab(self: *Elf) !void {
4457 const gpa = self.base.allocator;4682 const gpa = self.base.allocator;
4458 const shdr = &self.shdrs.items[self.symtab_section_index.?];4683 const symtab_shdr = self.shdrs.items[self.symtab_section_index.?];
4684 const strtab_shdr = self.shdrs.items[self.strtab_section_index.?];
4459 const sym_size: u64 = switch (self.ptr_width) {4685 const sym_size: u64 = switch (self.ptr_width) {
4460 .p32 => @sizeOf(elf.Elf32_Sym),4686 .p32 => @sizeOf(elf.Elf32_Sym),
4461 .p64 => @sizeOf(elf.Elf64_Sym),4687 .p64 => @sizeOf(elf.Elf64_Sym),
4462 };4688 };
4463 const nsyms = math.cast(usize, @divExact(shdr.sh_size, sym_size)) orelse return error.Overflow;4689 const nsyms = math.cast(usize, @divExact(symtab_shdr.sh_size, sym_size)) orelse return error.Overflow;
44644690
4465 log.debug("writing {d} symbols at 0x{x}", .{ nsyms, shdr.sh_offset });4691 log.debug("writing {d} symbols at 0x{x}", .{ nsyms, symtab_shdr.sh_offset });
44664692
4467 const symtab = try gpa.alloc(elf.Elf64_Sym, nsyms);4693 try self.symtab.resize(gpa, nsyms);
4468 defer gpa.free(symtab);4694 const needed_strtab_size = math.cast(usize, strtab_shdr.sh_size - 1) orelse return error.Overflow;
4469 symtab[0] = null_sym;4695 try self.strtab.ensureUnusedCapacity(gpa, needed_strtab_size);
44704696
4471 var ctx: struct { ilocal: usize, iglobal: usize, symtab: []elf.Elf64_Sym } = .{4697 const Ctx = struct {
4698 ilocal: usize,
4699 iglobal: usize,
4700
4701 fn incr(this: *@This(), ss: SymtabSize) void {
4702 this.ilocal += ss.nlocals;
4703 this.iglobal += ss.nglobals;
4704 }
4705 };
4706 var ctx: Ctx = .{
4472 .ilocal = 1,4707 .ilocal = 1,
4473 .iglobal = shdr.sh_info,4708 .iglobal = symtab_shdr.sh_info,
4474 .symtab = symtab,
4475 };4709 };
44764710
4477 if (self.zigObjectPtr()) |zig_object| {4711 if (self.zigObjectPtr()) |zig_object| {
4478 zig_object.writeSymtab(self, ctx);4712 zig_object.asFile().writeSymtab(self, ctx);
4479 ctx.ilocal += zig_object.output_symtab_size.nlocals;4713 ctx.incr(zig_object.output_symtab_size);
4480 ctx.iglobal += zig_object.output_symtab_size.nglobals;
4481 }4714 }
44824715
4483 for (self.objects.items) |index| {4716 for (self.objects.items) |index| {
4484 const object = self.file(index).?.object;4717 const file_ptr = self.file(index).?;
4485 object.writeSymtab(self, ctx);4718 file_ptr.writeSymtab(self, ctx);
4486 ctx.ilocal += object.output_symtab_size.nlocals;4719 ctx.incr(file_ptr.object.output_symtab_size);
4487 ctx.iglobal += object.output_symtab_size.nglobals;
4488 }4720 }
44894721
4490 for (self.shared_objects.items) |index| {4722 for (self.shared_objects.items) |index| {
4491 const shared_object = self.file(index).?.shared_object;4723 const file_ptr = self.file(index).?;
4492 shared_object.writeSymtab(self, ctx);4724 file_ptr.writeSymtab(self, ctx);
4493 ctx.iglobal += shared_object.output_symtab_size.nglobals;4725 ctx.incr(file_ptr.shared_object.output_symtab_size);
4494 }4726 }
44954727
4496 if (self.zig_got_section_index) |_| {4728 if (self.zig_got_section_index) |_| {
4497 try self.zig_got.writeSymtab(self, ctx);4729 self.zig_got.writeSymtab(self, ctx);
4498 ctx.ilocal += self.zig_got.output_symtab_size.nlocals;4730 ctx.incr(self.zig_got.output_symtab_size);
4499 }4731 }
45004732
4501 if (self.got_section_index) |_| {4733 if (self.got_section_index) |_| {
4502 try self.got.writeSymtab(self, ctx);4734 self.got.writeSymtab(self, ctx);
4503 ctx.ilocal += self.got.output_symtab_size.nlocals;4735 ctx.incr(self.got.output_symtab_size);
4504 }4736 }
45054737
4506 if (self.plt_section_index) |_| {4738 if (self.plt_section_index) |_| {
4507 try self.plt.writeSymtab(self, ctx);4739 self.plt.writeSymtab(self, ctx);
4508 ctx.ilocal += self.plt.output_symtab_size.nlocals;4740 ctx.incr(self.plt.output_symtab_size);
4509 }4741 }
45104742
4511 if (self.plt_got_section_index) |_| {4743 if (self.plt_got_section_index) |_| {
4512 try self.plt_got.writeSymtab(self, ctx);4744 self.plt_got.writeSymtab(self, ctx);
4513 ctx.ilocal += self.plt_got.output_symtab_size.nlocals;4745 ctx.incr(self.plt_got.output_symtab_size);
4514 }4746 }
45154747
4516 if (self.linker_defined_index) |index| {4748 if (self.linker_defined_index) |index| {
4517 const linker_defined = self.file(index).?.linker_defined;4749 const file_ptr = self.file(index).?;
4518 linker_defined.writeSymtab(self, ctx);4750 file_ptr.writeSymtab(self, ctx);
4519 ctx.ilocal += linker_defined.output_symtab_size.nlocals;4751 ctx.incr(file_ptr.linker_defined.output_symtab_size);
4520 }4752 }
45214753
4522 const foreign_endian = self.base.options.target.cpu.arch.endian() != builtin.cpu.arch.endian();4754 const foreign_endian = self.base.options.target.cpu.arch.endian() != builtin.cpu.arch.endian();
4523 switch (self.ptr_width) {4755 switch (self.ptr_width) {
4524 .p32 => {4756 .p32 => {
4525 const buf = try gpa.alloc(elf.Elf32_Sym, symtab.len);4757 const buf = try gpa.alloc(elf.Elf32_Sym, self.symtab.items.len);
4526 defer gpa.free(buf);4758 defer gpa.free(buf);
45274759
4528 for (buf, symtab) |*out, sym| {4760 for (buf, self.symtab.items) |*out, sym| {
4529 out.* = .{4761 out.* = .{
4530 .st_name = sym.st_name,4762 .st_name = sym.st_name,
4531 .st_info = sym.st_info,4763 .st_info = sym.st_info,
...@@ -4536,15 +4768,17 @@ fn writeSymtab(self: *Elf) !void {...@@ -4536,15 +4768,17 @@ fn writeSymtab(self: *Elf) !void {
4536 };4768 };
4537 if (foreign_endian) mem.byteSwapAllFields(elf.Elf32_Sym, out);4769 if (foreign_endian) mem.byteSwapAllFields(elf.Elf32_Sym, out);
4538 }4770 }
4539 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), shdr.sh_offset);4771 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), symtab_shdr.sh_offset);
4540 },4772 },
4541 .p64 => {4773 .p64 => {
4542 if (foreign_endian) {4774 if (foreign_endian) {
4543 for (symtab) |*sym| mem.byteSwapAllFields(elf.Elf64_Sym, sym);4775 for (self.symtab.items) |*sym| mem.byteSwapAllFields(elf.Elf64_Sym, sym);
4544 }4776 }
4545 try self.base.file.?.pwriteAll(mem.sliceAsBytes(symtab), shdr.sh_offset);4777 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.symtab.items), symtab_shdr.sh_offset);
4546 },4778 },
4547 }4779 }
4780
4781 try self.base.file.?.pwriteAll(self.strtab.items, strtab_shdr.sh_offset);
4548}4782}
45494783
4550/// Always 4 or 8 depending on whether this is 32-bit ELF or 64-bit ELF.4784/// Always 4 or 8 depending on whether this is 32-bit ELF or 64-bit ELF.
...@@ -4848,18 +5082,30 @@ pub fn isStatic(self: Elf) bool {...@@ -4848,18 +5082,30 @@ pub fn isStatic(self: Elf) bool {
4848 return self.base.options.link_mode == .Static;5082 return self.base.options.link_mode == .Static;
4849}5083}
48505084
5085pub fn isObject(self: Elf) bool {
5086 return self.base.options.output_mode == .Obj;
5087}
5088
4851pub fn isExe(self: Elf) bool {5089pub fn isExe(self: Elf) bool {
4852 return self.base.options.effectiveOutputMode() == .Exe;5090 return self.base.options.output_mode == .Exe;
5091}
5092
5093pub fn isStaticLib(self: Elf) bool {
5094 return self.base.options.output_mode == .Lib and self.isStatic();
5095}
5096
5097pub fn isRelocatable(self: Elf) bool {
5098 return self.isObject() or self.isStaticLib();
4853}5099}
48545100
4855pub fn isDynLib(self: Elf) bool {5101pub fn isDynLib(self: Elf) bool {
4856 return self.base.options.effectiveOutputMode() == .Lib and self.base.options.link_mode == .Dynamic;5102 return self.base.options.output_mode == .Lib and !self.isStatic();
4857}5103}
48585104
4859pub fn isZigSection(self: Elf, shndx: u16) bool {5105pub fn isZigSection(self: Elf, shndx: u16) bool {
4860 inline for (&[_]?u16{5106 inline for (&[_]?u16{
4861 self.zig_text_section_index,5107 self.zig_text_section_index,
4862 self.zig_rodata_section_index,5108 self.zig_data_rel_ro_section_index,
4863 self.zig_data_section_index,5109 self.zig_data_section_index,
4864 self.zig_bss_section_index,5110 self.zig_bss_section_index,
4865 self.zig_got_section_index,5111 self.zig_got_section_index,
...@@ -4909,6 +5155,26 @@ fn addPhdr(self: *Elf, opts: struct {...@@ -4909,6 +5155,26 @@ fn addPhdr(self: *Elf, opts: struct {
4909 return index;5155 return index;
4910}5156}
49115157
5158fn addRelaShdr(self: *Elf, name: [:0]const u8, shndx: u16) !u16 {
5159 const entsize: u64 = switch (self.ptr_width) {
5160 .p32 => @sizeOf(elf.Elf32_Rela),
5161 .p64 => @sizeOf(elf.Elf64_Rela),
5162 };
5163 const addralign: u64 = switch (self.ptr_width) {
5164 .p32 => @alignOf(elf.Elf32_Rela),
5165 .p64 => @alignOf(elf.Elf64_Rela),
5166 };
5167 return self.addSection(.{
5168 .name = name,
5169 .type = elf.SHT_RELA,
5170 .flags = elf.SHF_INFO_LINK,
5171 .entsize = entsize,
5172 .info = shndx,
5173 .addralign = addralign,
5174 .offset = std.math.maxInt(u64),
5175 });
5176}
5177
4912pub const AddSectionOpts = struct {5178pub const AddSectionOpts = struct {
4913 name: [:0]const u8,5179 name: [:0]const u8,
4914 type: u32 = elf.SHT_NULL,5180 type: u32 = elf.SHT_NULL,
...@@ -4925,7 +5191,7 @@ pub fn addSection(self: *Elf, opts: AddSectionOpts) !u16 {...@@ -4925,7 +5191,7 @@ pub fn addSection(self: *Elf, opts: AddSectionOpts) !u16 {
4925 const index = @as(u16, @intCast(self.shdrs.items.len));5191 const index = @as(u16, @intCast(self.shdrs.items.len));
4926 const shdr = try self.shdrs.addOne(gpa);5192 const shdr = try self.shdrs.addOne(gpa);
4927 shdr.* = .{5193 shdr.* = .{
4928 .sh_name = try self.shstrtab.insert(gpa, opts.name),5194 .sh_name = try self.insertShString(opts.name),
4929 .sh_type = opts.type,5195 .sh_type = opts.type,
4930 .sh_flags = opts.flags,5196 .sh_flags = opts.flags,
4931 .sh_addr = 0,5197 .sh_addr = 0,
...@@ -4941,7 +5207,7 @@ pub fn addSection(self: *Elf, opts: AddSectionOpts) !u16 {...@@ -4941,7 +5207,7 @@ pub fn addSection(self: *Elf, opts: AddSectionOpts) !u16 {
49415207
4942pub fn sectionByName(self: *Elf, name: [:0]const u8) ?u16 {5208pub fn sectionByName(self: *Elf, name: [:0]const u8) ?u16 {
4943 for (self.shdrs.items, 0..) |*shdr, i| {5209 for (self.shdrs.items, 0..) |*shdr, i| {
4944 const this_name = self.shstrtab.getAssumeExists(shdr.sh_name);5210 const this_name = self.getShString(shdr.sh_name);
4945 if (mem.eql(u8, this_name, name)) return @as(u16, @intCast(i));5211 if (mem.eql(u8, this_name, name)) return @as(u16, @intCast(i));
4946 } else return null;5212 } else return null;
4947}5213}
...@@ -5114,13 +5380,15 @@ const GetOrPutGlobalResult = struct {...@@ -5114,13 +5380,15 @@ const GetOrPutGlobalResult = struct {
5114 index: Symbol.Index,5380 index: Symbol.Index,
5115};5381};
51165382
5117pub fn getOrPutGlobal(self: *Elf, name_off: u32) !GetOrPutGlobalResult {5383pub fn getOrPutGlobal(self: *Elf, name: []const u8) !GetOrPutGlobalResult {
5118 const gpa = self.base.allocator;5384 const gpa = self.base.allocator;
5385 const name_off = try self.strings.insert(gpa, name);
5119 const gop = try self.resolver.getOrPut(gpa, name_off);5386 const gop = try self.resolver.getOrPut(gpa, name_off);
5120 if (!gop.found_existing) {5387 if (!gop.found_existing) {
5121 const index = try self.addSymbol();5388 const index = try self.addSymbol();
5122 const global = self.symbol(index);5389 const global = self.symbol(index);
5123 global.name_offset = name_off;5390 global.name_offset = name_off;
5391 global.flags.global = true;
5124 gop.value_ptr.* = index;5392 gop.value_ptr.* = index;
5125 }5393 }
5126 return .{5394 return .{
...@@ -5130,7 +5398,7 @@ pub fn getOrPutGlobal(self: *Elf, name_off: u32) !GetOrPutGlobalResult {...@@ -5130,7 +5398,7 @@ pub fn getOrPutGlobal(self: *Elf, name_off: u32) !GetOrPutGlobalResult {
5130}5398}
51315399
5132pub fn globalByName(self: *Elf, name: []const u8) ?Symbol.Index {5400pub fn globalByName(self: *Elf, name: []const u8) ?Symbol.Index {
5133 const name_off = self.strtab.getOffset(name) orelse return null;5401 const name_off = self.strings.getOffset(name) orelse return null;
5134 return self.resolver.get(name_off);5402 return self.resolver.get(name_off);
5135}5403}
51365404
...@@ -5148,8 +5416,9 @@ const GetOrCreateComdatGroupOwnerResult = struct {...@@ -5148,8 +5416,9 @@ const GetOrCreateComdatGroupOwnerResult = struct {
5148 index: ComdatGroupOwner.Index,5416 index: ComdatGroupOwner.Index,
5149};5417};
51505418
5151pub fn getOrCreateComdatGroupOwner(self: *Elf, off: u32) !GetOrCreateComdatGroupOwnerResult {5419pub fn getOrCreateComdatGroupOwner(self: *Elf, name: [:0]const u8) !GetOrCreateComdatGroupOwnerResult {
5152 const gpa = self.base.allocator;5420 const gpa = self.base.allocator;
5421 const off = try self.strings.insert(gpa, name);
5153 const gop = try self.comdat_groups_table.getOrPut(gpa, off);5422 const gop = try self.comdat_groups_table.getOrPut(gpa, off);
5154 if (!gop.found_existing) {5423 if (!gop.found_existing) {
5155 const index = @as(ComdatGroupOwner.Index, @intCast(self.comdat_groups_owners.items.len));5424 const index = @as(ComdatGroupOwner.Index, @intCast(self.comdat_groups_owners.items.len));
...@@ -5239,6 +5508,30 @@ fn addErrorWithNotesAssumeCapacity(self: *Elf, note_count: usize) error{OutOfMem...@@ -5239,6 +5508,30 @@ fn addErrorWithNotesAssumeCapacity(self: *Elf, note_count: usize) error{OutOfMem
5239 return .{ .index = index };5508 return .{ .index = index };
5240}5509}
52415510
5511pub fn getShString(self: Elf, off: u32) [:0]const u8 {
5512 assert(off < self.shstrtab.items.len);
5513 return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.shstrtab.items.ptr + off)), 0);
5514}
5515
5516pub fn insertShString(self: *Elf, name: [:0]const u8) error{OutOfMemory}!u32 {
5517 const off = @as(u32, @intCast(self.shstrtab.items.len));
5518 try self.shstrtab.ensureUnusedCapacity(self.base.allocator, name.len + 1);
5519 self.shstrtab.writer(self.base.allocator).print("{s}\x00", .{name}) catch unreachable;
5520 return off;
5521}
5522
5523pub fn getDynString(self: Elf, off: u32) [:0]const u8 {
5524 assert(off < self.dynstrtab.items.len);
5525 return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.dynstrtab.items.ptr + off)), 0);
5526}
5527
5528pub fn insertDynString(self: *Elf, name: []const u8) error{OutOfMemory}!u32 {
5529 const off = @as(u32, @intCast(self.dynstrtab.items.len));
5530 try self.dynstrtab.ensureUnusedCapacity(self.base.allocator, name.len + 1);
5531 self.dynstrtab.writer(self.base.allocator).print("{s}\x00", .{name}) catch unreachable;
5532 return off;
5533}
5534
5242fn reportUndefined(self: *Elf, undefs: anytype) !void {5535fn reportUndefined(self: *Elf, undefs: anytype) !void {
5243 const gpa = self.base.allocator;5536 const gpa = self.base.allocator;
5244 const max_notes = 4;5537 const max_notes = 4;
...@@ -5340,8 +5633,8 @@ fn formatShdr(...@@ -5340,8 +5633,8 @@ fn formatShdr(
5340 _ = unused_fmt_string;5633 _ = unused_fmt_string;
5341 const shdr = ctx.shdr;5634 const shdr = ctx.shdr;
5342 try writer.print("{s} : @{x} ({x}) : align({x}) : size({x})", .{5635 try writer.print("{s} : @{x} ({x}) : align({x}) : size({x})", .{
5343 ctx.elf_file.shstrtab.getAssumeExists(shdr.sh_name), shdr.sh_offset,5636 ctx.elf_file.getShString(shdr.sh_name), shdr.sh_offset,
5344 shdr.sh_addr, shdr.sh_addralign,5637 shdr.sh_addr, shdr.sh_addralign,
5345 shdr.sh_size,5638 shdr.sh_size,
5346 });5639 });
5347}5640}
...@@ -5444,6 +5737,7 @@ fn fmtDumpState(...@@ -5444,6 +5737,7 @@ fn fmtDumpState(
5444 }5737 }
5445 try writer.print("{}\n", .{self.got.fmt(self)});5738 try writer.print("{}\n", .{self.got.fmt(self)});
5446 try writer.print("{}\n", .{self.zig_got.fmt(self)});5739 try writer.print("{}\n", .{self.zig_got.fmt(self)});
5740
5447 try writer.writeAll("Output shdrs\n");5741 try writer.writeAll("Output shdrs\n");
5448 for (self.shdrs.items, 0..) |shdr, shndx| {5742 for (self.shdrs.items, 0..) |shdr, shndx| {
5449 try writer.print("shdr({d}) : phdr({?d}) : {}\n", .{5743 try writer.print("shdr({d}) : phdr({?d}) : {}\n", .{
...@@ -5516,6 +5810,13 @@ pub const ComdatGroup = struct {...@@ -5516,6 +5810,13 @@ pub const ComdatGroup = struct {
5516pub const SymtabSize = struct {5810pub const SymtabSize = struct {
5517 nlocals: u32 = 0,5811 nlocals: u32 = 0,
5518 nglobals: u32 = 0,5812 nglobals: u32 = 0,
5813 strsize: u32 = 0,
5814
5815 fn add(ss: *SymtabSize, other: SymtabSize) void {
5816 ss.nlocals += other.nlocals;
5817 ss.nglobals += other.nglobals;
5818 ss.strsize += other.strsize;
5819 }
5519};5820};
55205821
5521pub const null_sym = elf.Elf64_Sym{5822pub const null_sym = elf.Elf64_Sym{
...@@ -5621,7 +5922,7 @@ const PltSection = synthetic_sections.PltSection;...@@ -5621,7 +5922,7 @@ const PltSection = synthetic_sections.PltSection;
5621const PltGotSection = synthetic_sections.PltGotSection;5922const PltGotSection = synthetic_sections.PltGotSection;
5622const SharedObject = @import("Elf/SharedObject.zig");5923const SharedObject = @import("Elf/SharedObject.zig");
5623const Symbol = @import("Elf/Symbol.zig");5924const Symbol = @import("Elf/Symbol.zig");
5624const StringTable = @import("strtab.zig").StringTable;5925const StringTable = @import("StringTable.zig");
5625const TypedValue = @import("../TypedValue.zig");5926const TypedValue = @import("../TypedValue.zig");
5626const VerneedSection = synthetic_sections.VerneedSection;5927const VerneedSection = synthetic_sections.VerneedSection;
5627const ZigGotSection = synthetic_sections.ZigGotSection;5928const ZigGotSection = synthetic_sections.ZigGotSection;
src/link/Elf/Archive.zig+272-63
...@@ -4,20 +4,150 @@ data: []const u8,...@@ -4,20 +4,150 @@ data: []const u8,
4objects: std.ArrayListUnmanaged(Object) = .{},4objects: std.ArrayListUnmanaged(Object) = .{},
5strtab: []const u8 = &[0]u8{},5strtab: []const u8 = &[0]u8{},
66
7pub fn isArchive(path: []const u8) !bool {
8 const file = try std.fs.cwd().openFile(path, .{});
9 defer file.close();
10 const reader = file.reader();
11 const magic = reader.readBytesNoEof(SARMAG) catch return false;
12 if (!mem.eql(u8, &magic, ARMAG)) return false;
13 return true;
14}
15
16pub fn deinit(self: *Archive, allocator: Allocator) void {
17 allocator.free(self.path);
18 allocator.free(self.data);
19 self.objects.deinit(allocator);
20}
21
22pub fn parse(self: *Archive, elf_file: *Elf) !void {
23 const gpa = elf_file.base.allocator;
24
25 var stream = std.io.fixedBufferStream(self.data);
26 const reader = stream.reader();
27 _ = try reader.readBytesNoEof(SARMAG);
28
29 while (true) {
30 if (stream.pos >= self.data.len) break;
31
32 if (stream.pos % 2 != 0) {
33 stream.pos += 1;
34 }
35 const hdr = try reader.readStruct(ar_hdr);
36
37 if (!mem.eql(u8, &hdr.ar_fmag, ARFMAG)) {
38 // TODO convert into an error
39 log.debug(
40 "{s}: invalid header delimiter: expected '{s}', found '{s}'",
41 .{ self.path, std.fmt.fmtSliceEscapeLower(ARFMAG), std.fmt.fmtSliceEscapeLower(&hdr.ar_fmag) },
42 );
43 return;
44 }
45
46 const size = try hdr.size();
47 defer {
48 _ = stream.seekBy(size) catch {};
49 }
50
51 if (hdr.isSymtab()) continue;
52 if (hdr.isStrtab()) {
53 self.strtab = self.data[stream.pos..][0..size];
54 continue;
55 }
56
57 const name = ar_hdr.getValue(&hdr.ar_name);
58
59 if (mem.eql(u8, name, "__.SYMDEF") or mem.eql(u8, name, "__.SYMDEF SORTED")) continue;
60
61 const object_name = blk: {
62 if (name[0] == '/') {
63 const off = try std.fmt.parseInt(u32, name[1..], 10);
64 const object_name = self.getString(off);
65 break :blk try gpa.dupe(u8, object_name[0 .. object_name.len - 1]); // To account for trailing '/'
66 }
67 break :blk try gpa.dupe(u8, name);
68 };
69
70 const object = Object{
71 .archive = try gpa.dupe(u8, self.path),
72 .path = object_name,
73 .data = try gpa.dupe(u8, self.data[stream.pos..][0..size]),
74 .index = undefined,
75 .alive = false,
76 };
77
78 log.debug("extracting object '{s}' from archive '{s}'", .{ object.path, self.path });
79
80 try self.objects.append(gpa, object);
81 }
82}
83
84fn getString(self: Archive, off: u32) []const u8 {
85 assert(off < self.strtab.len);
86 return mem.sliceTo(@as([*:strtab_delimiter]const u8, @ptrCast(self.strtab.ptr + off)), 0);
87}
88
89pub fn setArHdr(opts: struct {
90 name: union(enum) {
91 symtab: void,
92 strtab: void,
93 name: []const u8,
94 name_off: u32,
95 },
96 size: u32,
97}) ar_hdr {
98 var hdr: ar_hdr = .{
99 .ar_name = undefined,
100 .ar_date = undefined,
101 .ar_uid = undefined,
102 .ar_gid = undefined,
103 .ar_mode = undefined,
104 .ar_size = undefined,
105 .ar_fmag = undefined,
106 };
107 @memset(mem.asBytes(&hdr), 0x20);
108 @memcpy(&hdr.ar_fmag, Archive.ARFMAG);
109
110 {
111 var stream = std.io.fixedBufferStream(&hdr.ar_name);
112 const writer = stream.writer();
113 switch (opts.name) {
114 .symtab => writer.print("{s}", .{Archive.SYM64NAME}) catch unreachable,
115 .strtab => writer.print("//", .{}) catch unreachable,
116 .name => |x| writer.print("{s}", .{x}) catch unreachable,
117 .name_off => |x| writer.print("/{d}", .{x}) catch unreachable,
118 }
119 }
120 {
121 var stream = std.io.fixedBufferStream(&hdr.ar_size);
122 stream.writer().print("{d}", .{opts.size}) catch unreachable;
123 }
124
125 return hdr;
126}
127
7// Archive files start with the ARMAG identifying string. Then follows a128// Archive files start with the ARMAG identifying string. Then follows a
8// `struct ar_hdr', and as many bytes of member file data as its `ar_size'129// `struct ar_hdr', and as many bytes of member file data as its `ar_size'
9// member indicates, for each member file.130// member indicates, for each member file.
10/// String that begins an archive file.131/// String that begins an archive file.
11pub const ARMAG: *const [SARMAG:0]u8 = "!<arch>\n";132pub const ARMAG: *const [SARMAG:0]u8 = "!<arch>\n";
12/// Size of that string.133/// Size of that string.
13pub const SARMAG: u4 = 8;134pub const SARMAG = 8;
14135
15/// String in ar_fmag at the end of each header.136/// String in ar_fmag at the end of each header.
16const ARFMAG: *const [2:0]u8 = "`\n";137const ARFMAG: *const [2:0]u8 = "`\n";
17138
139/// Strtab identifier
140const STRNAME: *const [2:0]u8 = "//";
141
142/// 32-bit symtab identifier
143const SYMNAME: *const [1:0]u8 = "/";
144
145/// 64-bit symtab identifier
18const SYM64NAME: *const [7:0]u8 = "/SYM64/";146const SYM64NAME: *const [7:0]u8 = "/SYM64/";
19147
20const ar_hdr = extern struct {148const strtab_delimiter = '\n';
149
150pub const ar_hdr = extern struct {
21 /// Member file name, sometimes / terminated.151 /// Member file name, sometimes / terminated.
22 ar_name: [16]u8,152 ar_name: [16]u8,
23153
...@@ -54,93 +184,170 @@ const ar_hdr = extern struct {...@@ -54,93 +184,170 @@ const ar_hdr = extern struct {
54 }184 }
55185
56 fn isStrtab(self: ar_hdr) bool {186 fn isStrtab(self: ar_hdr) bool {
57 return mem.eql(u8, getValue(&self.ar_name), "//");187 return mem.eql(u8, getValue(&self.ar_name), STRNAME);
58 }188 }
59189
60 fn isSymtab(self: ar_hdr) bool {190 fn isSymtab(self: ar_hdr) bool {
61 return mem.eql(u8, getValue(&self.ar_name), "/");191 return mem.eql(u8, getValue(&self.ar_name), SYMNAME) or mem.eql(u8, getValue(&self.ar_name), SYM64NAME);
62 }192 }
63};193};
64194
65pub fn isArchive(path: []const u8) !bool {195pub const ArSymtab = struct {
66 const file = try std.fs.cwd().openFile(path, .{});196 symtab: std.ArrayListUnmanaged(Entry) = .{},
67 defer file.close();197 strtab: StringTable = .{},
68 const reader = file.reader();
69 const magic = reader.readBytesNoEof(Archive.SARMAG) catch return false;
70 if (!mem.eql(u8, &magic, ARMAG)) return false;
71 return true;
72}
73198
74pub fn deinit(self: *Archive, allocator: Allocator) void {199 pub fn deinit(ar: *ArSymtab, allocator: Allocator) void {
75 allocator.free(self.path);200 ar.symtab.deinit(allocator);
76 allocator.free(self.data);201 ar.strtab.deinit(allocator);
77 self.objects.deinit(allocator);202 }
78}
79203
80pub fn parse(self: *Archive, elf_file: *Elf) !void {204 pub fn sort(ar: *ArSymtab) void {
81 const gpa = elf_file.base.allocator;205 mem.sort(Entry, ar.symtab.items, {}, Entry.lessThan);
206 }
82207
83 var stream = std.io.fixedBufferStream(self.data);208 pub fn size(ar: ArSymtab, kind: enum { p32, p64 }) usize {
84 const reader = stream.reader();209 const ptr_size: usize = switch (kind) {
85 _ = try reader.readBytesNoEof(SARMAG);210 .p32 => 4,
211 .p64 => 8,
212 };
213 var ss: usize = ptr_size + ar.symtab.items.len * ptr_size;
214 for (ar.symtab.items) |entry| {
215 ss += ar.strtab.getAssumeExists(entry.off).len + 1;
216 }
217 return ss;
218 }
86219
87 while (true) {220 pub fn write(ar: ArSymtab, kind: enum { p32, p64 }, elf_file: *Elf, writer: anytype) !void {
88 if (stream.pos % 2 != 0) {221 assert(kind == .p64); // TODO p32
89 stream.pos += 1;222 const hdr = setArHdr(.{ .name = .symtab, .size = @intCast(ar.size(.p64)) });
223 try writer.writeAll(mem.asBytes(&hdr));
224
225 const gpa = elf_file.base.allocator;
226 var offsets = std.AutoHashMap(File.Index, u64).init(gpa);
227 defer offsets.deinit();
228 try offsets.ensureUnusedCapacity(@intCast(elf_file.objects.items.len + 1));
229
230 if (elf_file.zigObjectPtr()) |zig_object| {
231 offsets.putAssumeCapacityNoClobber(zig_object.index, zig_object.output_ar_state.file_off);
90 }232 }
91233
92 const hdr = reader.readStruct(ar_hdr) catch break;234 // Number of symbols
235 try writer.writeInt(u64, @as(u64, @intCast(ar.symtab.items.len)), .big);
93236
94 if (!mem.eql(u8, &hdr.ar_fmag, ARFMAG)) {237 // Offsets to files
95 // TODO convert into an error238 for (ar.symtab.items) |entry| {
96 log.debug(239 const off = offsets.get(entry.file_index).?;
97 "{s}: invalid header delimiter: expected '{s}', found '{s}'",240 try writer.writeInt(u64, off, .big);
98 .{ self.path, std.fmt.fmtSliceEscapeLower(ARFMAG), std.fmt.fmtSliceEscapeLower(&hdr.ar_fmag) },
99 );
100 return;
101 }241 }
102242
103 const size = try hdr.size();243 // Strings
104 defer {244 for (ar.symtab.items) |entry| {
105 _ = stream.seekBy(size) catch {};245 try writer.print("{s}\x00", .{ar.strtab.getAssumeExists(entry.off)});
106 }246 }
247 }
107248
108 if (hdr.isSymtab()) continue;249 pub fn format(
109 if (hdr.isStrtab()) {250 ar: ArSymtab,
110 self.strtab = self.data[stream.pos..][0..size];251 comptime unused_fmt_string: []const u8,
111 continue;252 options: std.fmt.FormatOptions,
253 writer: anytype,
254 ) !void {
255 _ = ar;
256 _ = unused_fmt_string;
257 _ = options;
258 _ = writer;
259 @compileError("do not format ar symtab directly; use fmt instead");
260 }
261
262 const FormatContext = struct {
263 ar: ArSymtab,
264 elf_file: *Elf,
265 };
266
267 pub fn fmt(ar: ArSymtab, elf_file: *Elf) std.fmt.Formatter(format2) {
268 return .{ .data = .{
269 .ar = ar,
270 .elf_file = elf_file,
271 } };
272 }
273
274 fn format2(
275 ctx: FormatContext,
276 comptime unused_fmt_string: []const u8,
277 options: std.fmt.FormatOptions,
278 writer: anytype,
279 ) !void {
280 _ = unused_fmt_string;
281 _ = options;
282 const ar = ctx.ar;
283 const elf_file = ctx.elf_file;
284 for (ar.symtab.items, 0..) |entry, i| {
285 const name = ar.strtab.getAssumeExists(entry.off);
286 const file = elf_file.file(entry.file_index).?;
287 try writer.print(" {d}: {s} in file({d})({})\n", .{ i, name, entry.file_index, file.fmtPath() });
112 }288 }
289 }
113290
114 const name = ar_hdr.getValue(&hdr.ar_name);291 const Entry = struct {
292 /// Offset into the string table.
293 off: u32,
294 /// Index of the file defining the global.
295 file_index: File.Index,
115296
116 if (mem.eql(u8, name, "__.SYMDEF") or mem.eql(u8, name, "__.SYMDEF SORTED")) continue;297 pub fn lessThan(ctx: void, lhs: Entry, rhs: Entry) bool {
298 _ = ctx;
299 if (lhs.off == rhs.off) return lhs.file_index < rhs.file_index;
300 return lhs.off < rhs.off;
301 }
302 };
303};
117304
118 const object_name = blk: {305pub const ArStrtab = struct {
119 if (name[0] == '/') {306 buffer: std.ArrayListUnmanaged(u8) = .{},
120 const off = try std.fmt.parseInt(u32, name[1..], 10);
121 break :blk self.getString(off);
122 }
123 break :blk name;
124 };
125307
126 const object = Object{308 pub fn deinit(ar: *ArStrtab, allocator: Allocator) void {
127 .archive = try gpa.dupe(u8, self.path),309 ar.buffer.deinit(allocator);
128 .path = try gpa.dupe(u8, object_name[0 .. object_name.len - 1]), // To account for trailing '/'310 }
129 .data = try gpa.dupe(u8, self.data[stream.pos..][0..size]),
130 .index = undefined,
131 .alive = false,
132 };
133311
134 log.debug("extracting object '{s}' from archive '{s}'", .{ object.path, self.path });312 pub fn insert(ar: *ArStrtab, allocator: Allocator, name: []const u8) error{OutOfMemory}!u32 {
313 const off = @as(u32, @intCast(ar.buffer.items.len));
314 try ar.buffer.writer(allocator).print("{s}/{c}", .{ name, strtab_delimiter });
315 return off;
316 }
135317
136 try self.objects.append(gpa, object);318 pub fn size(ar: ArStrtab) usize {
319 return ar.buffer.items.len;
137 }320 }
138}
139321
140fn getString(self: Archive, off: u32) []const u8 {322 pub fn write(ar: ArStrtab, writer: anytype) !void {
141 assert(off < self.strtab.len);323 const hdr = setArHdr(.{ .name = .strtab, .size = @intCast(ar.size()) });
142 return mem.sliceTo(@as([*:'\n']const u8, @ptrCast(self.strtab.ptr + off)), 0);324 try writer.writeAll(mem.asBytes(&hdr));
143}325 try writer.writeAll(ar.buffer.items);
326 }
327
328 pub fn format(
329 ar: ArStrtab,
330 comptime unused_fmt_string: []const u8,
331 options: std.fmt.FormatOptions,
332 writer: anytype,
333 ) !void {
334 _ = unused_fmt_string;
335 _ = options;
336 try writer.print("{s}", .{std.fmt.fmtSliceEscapeLower(ar.buffer.items)});
337 }
338};
339
340pub const ArState = struct {
341 /// Name offset in the string table.
342 name_off: u32 = 0,
343
344 /// File offset of the ar_hdr describing the contributing
345 /// object in the archive.
346 file_off: u64 = 0,
347
348 /// Total size of the contributing object (excludes ar_hdr).
349 size: u64 = 0,
350};
144351
145const std = @import("std");352const std = @import("std");
146const assert = std.debug.assert;353const assert = std.debug.assert;
...@@ -152,4 +359,6 @@ const mem = std.mem;...@@ -152,4 +359,6 @@ const mem = std.mem;
152const Allocator = mem.Allocator;359const Allocator = mem.Allocator;
153const Archive = @This();360const Archive = @This();
154const Elf = @import("../Elf.zig");361const Elf = @import("../Elf.zig");
362const File = @import("file.zig").File;
155const Object = @import("Object.zig");363const Object = @import("Object.zig");
364const StringTable = @import("../StringTable.zig");
src/link/Elf/Atom.zig+7-3
...@@ -42,7 +42,10 @@ next_index: Index = 0,...@@ -42,7 +42,10 @@ next_index: Index = 0,
42pub const Alignment = @import("../../InternPool.zig").Alignment;42pub const Alignment = @import("../../InternPool.zig").Alignment;
4343
44pub fn name(self: Atom, elf_file: *Elf) []const u8 {44pub fn name(self: Atom, elf_file: *Elf) []const u8 {
45 return elf_file.strtab.getAssumeExists(self.name_offset);45 const file_ptr = self.file(elf_file).?;
46 return switch (file_ptr) {
47 inline else => |x| x.getString(self.name_offset),
48 };
46}49}
4750
48pub fn file(self: Atom, elf_file: *Elf) ?File {51pub fn file(self: Atom, elf_file: *Elf) ?File {
...@@ -602,7 +605,8 @@ fn dynAbsRelocAction(symbol: *const Symbol, elf_file: *Elf) RelocAction {...@@ -602,7 +605,8 @@ fn dynAbsRelocAction(symbol: *const Symbol, elf_file: *Elf) RelocAction {
602}605}
603606
604fn outputType(elf_file: *Elf) u2 {607fn outputType(elf_file: *Elf) u2 {
605 return switch (elf_file.base.options.effectiveOutputMode()) {608 assert(!elf_file.isRelocatable());
609 return switch (elf_file.base.options.output_mode) {
606 .Obj => unreachable,610 .Obj => unreachable,
607 .Lib => 0,611 .Lib => 0,
608 .Exe => if (elf_file.base.options.pie) 1 else 2,612 .Exe => if (elf_file.base.options.pie) 1 else 2,
...@@ -692,7 +696,7 @@ fn reportUndefined(...@@ -692,7 +696,7 @@ fn reportUndefined(
692) !void {696) !void {
693 const rel_esym = switch (self.file(elf_file).?) {697 const rel_esym = switch (self.file(elf_file).?) {
694 .zig_object => |x| x.elfSym(rel.r_sym()).*,698 .zig_object => |x| x.elfSym(rel.r_sym()).*,
695 .object => |x| x.symtab[rel.r_sym()],699 .object => |x| x.symtab.items[rel.r_sym()],
696 else => unreachable,700 else => unreachable,
697 };701 };
698 const esym = sym.elfSym(elf_file);702 const esym = sym.elfSym(elf_file);
src/link/Elf/LinkerDefined.zig+15-27
...@@ -1,11 +1,13 @@...@@ -1,11 +1,13 @@
1index: File.Index,1index: File.Index,
2symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},2symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
3strtab: std.ArrayListUnmanaged(u8) = .{},
3symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},4symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
45
5output_symtab_size: Elf.SymtabSize = .{},6output_symtab_size: Elf.SymtabSize = .{},
67
7pub fn deinit(self: *LinkerDefined, allocator: Allocator) void {8pub fn deinit(self: *LinkerDefined, allocator: Allocator) void {
8 self.symtab.deinit(allocator);9 self.symtab.deinit(allocator);
10 self.strtab.deinit(allocator);
9 self.symbols.deinit(allocator);11 self.symbols.deinit(allocator);
10}12}
1113
...@@ -13,16 +15,17 @@ pub fn addGlobal(self: *LinkerDefined, name: [:0]const u8, elf_file: *Elf) !u32...@@ -13,16 +15,17 @@ pub fn addGlobal(self: *LinkerDefined, name: [:0]const u8, elf_file: *Elf) !u32
13 const gpa = elf_file.base.allocator;15 const gpa = elf_file.base.allocator;
14 try self.symtab.ensureUnusedCapacity(gpa, 1);16 try self.symtab.ensureUnusedCapacity(gpa, 1);
15 try self.symbols.ensureUnusedCapacity(gpa, 1);17 try self.symbols.ensureUnusedCapacity(gpa, 1);
18 const name_off = @as(u32, @intCast(self.strtab.items.len));
19 try self.strtab.writer(gpa).print("{s}\x00", .{name});
16 self.symtab.appendAssumeCapacity(.{20 self.symtab.appendAssumeCapacity(.{
17 .st_name = try elf_file.strtab.insert(gpa, name),21 .st_name = name_off,
18 .st_info = elf.STB_GLOBAL << 4,22 .st_info = elf.STB_GLOBAL << 4,
19 .st_other = @intFromEnum(elf.STV.HIDDEN),23 .st_other = @intFromEnum(elf.STV.HIDDEN),
20 .st_shndx = elf.SHN_ABS,24 .st_shndx = elf.SHN_ABS,
21 .st_value = 0,25 .st_value = 0,
22 .st_size = 0,26 .st_size = 0,
23 });27 });
24 const off = try elf_file.strtab.insert(gpa, name);28 const gop = try elf_file.getOrPutGlobal(name);
25 const gop = try elf_file.getOrPutGlobal(off);
26 self.symbols.addOneAssumeCapacity().* = gop.index;29 self.symbols.addOneAssumeCapacity().* = gop.index;
27 return gop.index;30 return gop.index;
28}31}
...@@ -37,7 +40,6 @@ pub fn resolveSymbols(self: *LinkerDefined, elf_file: *Elf) void {...@@ -37,7 +40,6 @@ pub fn resolveSymbols(self: *LinkerDefined, elf_file: *Elf) void {
37 const global = elf_file.symbol(index);40 const global = elf_file.symbol(index);
38 if (self.asFile().symbolRank(this_sym, false) < global.symbolRank(elf_file)) {41 if (self.asFile().symbolRank(this_sym, false) < global.symbolRank(elf_file)) {
39 global.value = 0;42 global.value = 0;
40 global.name_offset = global.name_offset;
41 global.atom_index = 0;43 global.atom_index = 0;
42 global.file_index = self.index;44 global.file_index = self.index;
43 global.esym_index = sym_idx;45 global.esym_index = sym_idx;
...@@ -46,26 +48,6 @@ pub fn resolveSymbols(self: *LinkerDefined, elf_file: *Elf) void {...@@ -46,26 +48,6 @@ pub fn resolveSymbols(self: *LinkerDefined, elf_file: *Elf) void {
46 }48 }
47}49}
4850
49pub fn updateSymtabSize(self: *LinkerDefined, elf_file: *Elf) void {
50 for (self.globals()) |global_index| {
51 const global = elf_file.symbol(global_index);
52 if (global.file(elf_file)) |file| if (file.index() != self.index) continue;
53 global.flags.output_symtab = true;
54 self.output_symtab_size.nlocals += 1;
55 }
56}
57
58pub fn writeSymtab(self: *LinkerDefined, elf_file: *Elf, ctx: anytype) void {
59 var ilocal = ctx.ilocal;
60 for (self.globals()) |global_index| {
61 const global = elf_file.symbol(global_index);
62 if (global.file(elf_file)) |file| if (file.index() != self.index) continue;
63 if (!global.flags.output_symtab) continue;
64 global.setOutputSym(elf_file, &ctx.symtab[ilocal]);
65 ilocal += 1;
66 }
67}
68
69pub fn globals(self: *LinkerDefined) []const Symbol.Index {51pub fn globals(self: *LinkerDefined) []const Symbol.Index {
70 return self.symbols.items;52 return self.symbols.items;
71}53}
...@@ -74,6 +56,11 @@ pub fn asFile(self: *LinkerDefined) File {...@@ -74,6 +56,11 @@ pub fn asFile(self: *LinkerDefined) File {
74 return .{ .linker_defined = self };56 return .{ .linker_defined = self };
75}57}
7658
59pub fn getString(self: LinkerDefined, off: u32) [:0]const u8 {
60 assert(off < self.strtab.items.len);
61 return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0);
62}
63
77pub fn fmtSymtab(self: *LinkerDefined, elf_file: *Elf) std.fmt.Formatter(formatSymtab) {64pub fn fmtSymtab(self: *LinkerDefined, elf_file: *Elf) std.fmt.Formatter(formatSymtab) {
78 return .{ .data = .{65 return .{ .data = .{
79 .self = self,66 .self = self,
...@@ -101,12 +88,13 @@ fn formatSymtab(...@@ -101,12 +88,13 @@ fn formatSymtab(
101 }88 }
102}89}
10390
104const std = @import("std");91const assert = std.debug.assert;
105const elf = std.elf;92const elf = std.elf;
93const mem = std.mem;
94const std = @import("std");
10695
107const Allocator = std.mem.Allocator;96const Allocator = mem.Allocator;
108const Elf = @import("../Elf.zig");97const Elf = @import("../Elf.zig");
109const File = @import("file.zig").File;98const File = @import("file.zig").File;
110const LinkerDefined = @This();99const LinkerDefined = @This();
111// const Object = @import("Object.zig");
112const Symbol = @import("Symbol.zig");100const Symbol = @import("Symbol.zig");
src/link/Elf/Object.zig+51-116
...@@ -5,11 +5,10 @@ index: File.Index,...@@ -5,11 +5,10 @@ index: File.Index,
55
6header: ?elf.Elf64_Ehdr = null,6header: ?elf.Elf64_Ehdr = null,
7shdrs: std.ArrayListUnmanaged(ElfShdr) = .{},7shdrs: std.ArrayListUnmanaged(ElfShdr) = .{},
8strings: StringTable(.object_strings) = .{},
9symtab: []align(1) const elf.Elf64_Sym = &[0]elf.Elf64_Sym{},
10strtab: []const u8 = &[0]u8{},
11first_global: ?Symbol.Index = null,
128
9symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
10strtab: std.ArrayListUnmanaged(u8) = .{},
11first_global: ?Symbol.Index = null,
13symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},12symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
14atoms: std.ArrayListUnmanaged(Atom.Index) = .{},13atoms: std.ArrayListUnmanaged(Atom.Index) = .{},
15comdat_groups: std.ArrayListUnmanaged(Elf.ComdatGroup.Index) = .{},14comdat_groups: std.ArrayListUnmanaged(Elf.ComdatGroup.Index) = .{},
...@@ -39,7 +38,8 @@ pub fn deinit(self: *Object, allocator: Allocator) void {...@@ -39,7 +38,8 @@ pub fn deinit(self: *Object, allocator: Allocator) void {
39 allocator.free(self.path);38 allocator.free(self.path);
40 allocator.free(self.data);39 allocator.free(self.data);
41 self.shdrs.deinit(allocator);40 self.shdrs.deinit(allocator);
42 self.strings.deinit(allocator);41 self.symtab.deinit(allocator);
42 self.strtab.deinit(allocator);
43 self.symbols.deinit(allocator);43 self.symbols.deinit(allocator);
44 self.atoms.deinit(allocator);44 self.atoms.deinit(allocator);
45 self.comdat_groups.deinit(allocator);45 self.comdat_groups.deinit(allocator);
...@@ -68,7 +68,7 @@ pub fn parse(self: *Object, elf_file: *Elf) !void {...@@ -68,7 +68,7 @@ pub fn parse(self: *Object, elf_file: *Elf) !void {
68 self.shdrs.appendAssumeCapacity(try ElfShdr.fromElf64Shdr(shdr));68 self.shdrs.appendAssumeCapacity(try ElfShdr.fromElf64Shdr(shdr));
69 }69 }
7070
71 try self.strings.buffer.appendSlice(gpa, self.shdrContents(self.header.?.e_shstrndx));71 try self.strtab.appendSlice(gpa, self.shdrContents(self.header.?.e_shstrndx));
7272
73 const symtab_index = for (self.shdrs.items, 0..) |shdr, i| switch (shdr.sh_type) {73 const symtab_index = for (self.shdrs.items, 0..) |shdr, i| switch (shdr.sh_type) {
74 elf.SHT_SYMTAB => break @as(u16, @intCast(i)),74 elf.SHT_SYMTAB => break @as(u16, @intCast(i)),
...@@ -79,10 +79,22 @@ pub fn parse(self: *Object, elf_file: *Elf) !void {...@@ -79,10 +79,22 @@ pub fn parse(self: *Object, elf_file: *Elf) !void {
79 const shdr = shdrs[index];79 const shdr = shdrs[index];
80 self.first_global = shdr.sh_info;80 self.first_global = shdr.sh_info;
8181
82 const symtab = self.shdrContents(index);82 const raw_symtab = self.shdrContents(index);
83 const nsyms = @divExact(symtab.len, @sizeOf(elf.Elf64_Sym));83 const nsyms = @divExact(raw_symtab.len, @sizeOf(elf.Elf64_Sym));
84 self.symtab = @as([*]align(1) const elf.Elf64_Sym, @ptrCast(symtab.ptr))[0..nsyms];84 const symtab = @as([*]align(1) const elf.Elf64_Sym, @ptrCast(raw_symtab.ptr))[0..nsyms];
85 self.strtab = self.shdrContents(@as(u16, @intCast(shdr.sh_link)));85
86 const strtab_bias = @as(u32, @intCast(self.strtab.items.len));
87 try self.strtab.appendSlice(gpa, self.shdrContents(@as(u16, @intCast(shdr.sh_link))));
88
89 try self.symtab.ensureUnusedCapacity(gpa, symtab.len);
90 for (symtab) |sym| {
91 const out_sym = self.symtab.addOneAssumeCapacity();
92 out_sym.* = sym;
93 out_sym.st_name = if (sym.st_name == 0 and sym.st_type() == elf.STT_SECTION)
94 shdrs[sym.st_shndx].sh_name
95 else
96 sym.st_name + strtab_bias;
97 }
86 }98 }
8799
88 try self.initAtoms(elf_file);100 try self.initAtoms(elf_file);
...@@ -108,16 +120,16 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void {...@@ -108,16 +120,16 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void {
108120
109 switch (shdr.sh_type) {121 switch (shdr.sh_type) {
110 elf.SHT_GROUP => {122 elf.SHT_GROUP => {
111 if (shdr.sh_info >= self.symtab.len) {123 if (shdr.sh_info >= self.symtab.items.len) {
112 // TODO convert into an error124 // TODO convert into an error
113 log.debug("{}: invalid symbol index in sh_info", .{self.fmtPath()});125 log.debug("{}: invalid symbol index in sh_info", .{self.fmtPath()});
114 continue;126 continue;
115 }127 }
116 const group_info_sym = self.symtab[shdr.sh_info];128 const group_info_sym = self.symtab.items[shdr.sh_info];
117 const group_signature = blk: {129 const group_signature = blk: {
118 if (group_info_sym.st_name == 0 and group_info_sym.st_type() == elf.STT_SECTION) {130 if (group_info_sym.st_name == 0 and group_info_sym.st_type() == elf.STT_SECTION) {
119 const sym_shdr = shdrs[group_info_sym.st_shndx];131 const sym_shdr = shdrs[group_info_sym.st_shndx];
120 break :blk self.strings.getAssumeExists(sym_shdr.sh_name);132 break :blk self.getString(sym_shdr.sh_name);
121 }133 }
122 break :blk self.getString(group_info_sym.st_name);134 break :blk self.getString(group_info_sym.st_name);
123 };135 };
...@@ -133,11 +145,8 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void {...@@ -133,11 +145,8 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void {
133 continue;145 continue;
134 }146 }
135147
136 // Note the assumption about a global strtab used here to disambiguate common
137 // COMDAT owners.
138 const gpa = elf_file.base.allocator;148 const gpa = elf_file.base.allocator;
139 const group_signature_off = try elf_file.strtab.insert(gpa, group_signature);149 const gop = try elf_file.getOrCreateComdatGroupOwner(group_signature);
140 const gop = try elf_file.getOrCreateComdatGroupOwner(group_signature_off);
141 const comdat_group_index = try elf_file.addComdatGroup();150 const comdat_group_index = try elf_file.addComdatGroup();
142 const comdat_group = elf_file.comdatGroup(comdat_group_index);151 const comdat_group = elf_file.comdatGroup(comdat_group_index);
143 comdat_group.* = .{152 comdat_group.* = .{
...@@ -157,10 +166,9 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void {...@@ -157,10 +166,9 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void {
157 => {},166 => {},
158167
159 else => {168 else => {
160 const name = self.strings.getAssumeExists(shdr.sh_name);
161 const shndx = @as(u16, @intCast(i));169 const shndx = @as(u16, @intCast(i));
162 if (self.skipShdr(shndx, elf_file)) continue;170 if (self.skipShdr(shndx, elf_file)) continue;
163 try self.addAtom(shdr, shndx, name, elf_file);171 try self.addAtom(shdr, shndx, elf_file);
164 },172 },
165 }173 }
166 }174 }
...@@ -177,17 +185,11 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void {...@@ -177,17 +185,11 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void {
177 };185 };
178}186}
179187
180fn addAtom(188fn addAtom(self: *Object, shdr: ElfShdr, shndx: u16, elf_file: *Elf) error{OutOfMemory}!void {
181 self: *Object,
182 shdr: ElfShdr,
183 shndx: u16,
184 name: [:0]const u8,
185 elf_file: *Elf,
186) error{OutOfMemory}!void {
187 const atom_index = try elf_file.addAtom();189 const atom_index = try elf_file.addAtom();
188 const atom = elf_file.atom(atom_index).?;190 const atom = elf_file.atom(atom_index).?;
189 atom.atom_index = atom_index;191 atom.atom_index = atom_index;
190 atom.name_offset = try elf_file.strtab.insert(elf_file.base.allocator, name);192 atom.name_offset = shdr.sh_name;
191 atom.file_index = self.index;193 atom.file_index = self.index;
192 atom.input_section_index = shndx;194 atom.input_section_index = shndx;
193 self.atoms.items[shndx] = atom_index;195 self.atoms.items[shndx] = atom_index;
...@@ -205,7 +207,7 @@ fn addAtom(...@@ -205,7 +207,7 @@ fn addAtom(
205207
206fn initOutputSection(self: Object, elf_file: *Elf, shdr: ElfShdr) error{OutOfMemory}!u16 {208fn initOutputSection(self: Object, elf_file: *Elf, shdr: ElfShdr) error{OutOfMemory}!u16 {
207 const name = blk: {209 const name = blk: {
208 const name = self.strings.getAssumeExists(shdr.sh_name);210 const name = self.getString(shdr.sh_name);
209 if (shdr.sh_flags & elf.SHF_MERGE != 0) break :blk name;211 if (shdr.sh_flags & elf.SHF_MERGE != 0) break :blk name;
210 const sh_name_prefixes: []const [:0]const u8 = &.{212 const sh_name_prefixes: []const [:0]const u8 = &.{
211 ".text", ".data.rel.ro", ".data", ".rodata", ".bss.rel.ro", ".bss",213 ".text", ".data.rel.ro", ".data", ".rodata", ".bss.rel.ro", ".bss",
...@@ -248,7 +250,7 @@ fn initOutputSection(self: Object, elf_file: *Elf, shdr: ElfShdr) error{OutOfMem...@@ -248,7 +250,7 @@ fn initOutputSection(self: Object, elf_file: *Elf, shdr: ElfShdr) error{OutOfMem
248250
249fn skipShdr(self: *Object, index: u16, elf_file: *Elf) bool {251fn skipShdr(self: *Object, index: u16, elf_file: *Elf) bool {
250 const shdr = self.shdrs.items[index];252 const shdr = self.shdrs.items[index];
251 const name = self.strings.getAssumeExists(shdr.sh_name);253 const name = self.getString(shdr.sh_name);
252 const ignore = blk: {254 const ignore = blk: {
253 if (mem.startsWith(u8, name, ".note")) break :blk true;255 if (mem.startsWith(u8, name, ".note")) break :blk true;
254 if (mem.startsWith(u8, name, ".comment")) break :blk true;256 if (mem.startsWith(u8, name, ".comment")) break :blk true;
...@@ -262,33 +264,24 @@ fn skipShdr(self: *Object, index: u16, elf_file: *Elf) bool {...@@ -262,33 +264,24 @@ fn skipShdr(self: *Object, index: u16, elf_file: *Elf) bool {
262264
263fn initSymtab(self: *Object, elf_file: *Elf) !void {265fn initSymtab(self: *Object, elf_file: *Elf) !void {
264 const gpa = elf_file.base.allocator;266 const gpa = elf_file.base.allocator;
265 const first_global = self.first_global orelse self.symtab.len;267 const first_global = self.first_global orelse self.symtab.items.len;
266 const shdrs = self.shdrs.items;
267268
268 try self.symbols.ensureTotalCapacityPrecise(gpa, self.symtab.len);269 try self.symbols.ensureTotalCapacityPrecise(gpa, self.symtab.items.len);
269270
270 for (self.symtab[0..first_global], 0..) |sym, i| {271 for (self.symtab.items[0..first_global], 0..) |sym, i| {
271 const index = try elf_file.addSymbol();272 const index = try elf_file.addSymbol();
272 self.symbols.appendAssumeCapacity(index);273 self.symbols.appendAssumeCapacity(index);
273 const sym_ptr = elf_file.symbol(index);274 const sym_ptr = elf_file.symbol(index);
274 const name = blk: {
275 if (sym.st_name == 0 and sym.st_type() == elf.STT_SECTION) {
276 const shdr = shdrs[sym.st_shndx];
277 break :blk self.strings.getAssumeExists(shdr.sh_name);
278 }
279 break :blk self.getString(sym.st_name);
280 };
281 sym_ptr.value = sym.st_value;275 sym_ptr.value = sym.st_value;
282 sym_ptr.name_offset = try elf_file.strtab.insert(gpa, name);276 sym_ptr.name_offset = sym.st_name;
283 sym_ptr.esym_index = @as(u32, @intCast(i));277 sym_ptr.esym_index = @as(u32, @intCast(i));
284 sym_ptr.atom_index = if (sym.st_shndx == elf.SHN_ABS) 0 else self.atoms.items[sym.st_shndx];278 sym_ptr.atom_index = if (sym.st_shndx == elf.SHN_ABS) 0 else self.atoms.items[sym.st_shndx];
285 sym_ptr.file_index = self.index;279 sym_ptr.file_index = self.index;
286 }280 }
287281
288 for (self.symtab[first_global..]) |sym| {282 for (self.symtab.items[first_global..]) |sym| {
289 const name = self.getString(sym.st_name);283 const name = self.getString(sym.st_name);
290 const off = try elf_file.strtab.insert(gpa, name);284 const gop = try elf_file.getOrPutGlobal(name);
291 const gop = try elf_file.getOrPutGlobal(off);
292 self.symbols.addOneAssumeCapacity().* = gop.index;285 self.symbols.addOneAssumeCapacity().* = gop.index;
293 }286 }
294}287}
...@@ -437,7 +430,7 @@ pub fn resolveSymbols(self: *Object, elf_file: *Elf) void {...@@ -437,7 +430,7 @@ pub fn resolveSymbols(self: *Object, elf_file: *Elf) void {
437 const first_global = self.first_global orelse return;430 const first_global = self.first_global orelse return;
438 for (self.globals(), 0..) |index, i| {431 for (self.globals(), 0..) |index, i| {
439 const esym_index = @as(Symbol.Index, @intCast(first_global + i));432 const esym_index = @as(Symbol.Index, @intCast(first_global + i));
440 const esym = self.symtab[esym_index];433 const esym = self.symtab.items[esym_index];
441434
442 if (esym.st_shndx == elf.SHN_UNDEF) continue;435 if (esym.st_shndx == elf.SHN_UNDEF) continue;
443436
...@@ -467,7 +460,7 @@ pub fn claimUnresolved(self: *Object, elf_file: *Elf) void {...@@ -467,7 +460,7 @@ pub fn claimUnresolved(self: *Object, elf_file: *Elf) void {
467 const first_global = self.first_global orelse return;460 const first_global = self.first_global orelse return;
468 for (self.globals(), 0..) |index, i| {461 for (self.globals(), 0..) |index, i| {
469 const esym_index = @as(u32, @intCast(first_global + i));462 const esym_index = @as(u32, @intCast(first_global + i));
470 const esym = self.symtab[esym_index];463 const esym = self.symtab.items[esym_index];
471 if (esym.st_shndx != elf.SHN_UNDEF) continue;464 if (esym.st_shndx != elf.SHN_UNDEF) continue;
472465
473 const global = elf_file.symbol(index);466 const global = elf_file.symbol(index);
...@@ -491,20 +484,11 @@ pub fn claimUnresolved(self: *Object, elf_file: *Elf) void {...@@ -491,20 +484,11 @@ pub fn claimUnresolved(self: *Object, elf_file: *Elf) void {
491 }484 }
492}485}
493486
494pub fn resetGlobals(self: *Object, elf_file: *Elf) void {
495 for (self.globals()) |index| {
496 const global = elf_file.symbol(index);
497 const off = global.name_offset;
498 global.* = .{};
499 global.name_offset = off;
500 }
501}
502
503pub fn markLive(self: *Object, elf_file: *Elf) void {487pub fn markLive(self: *Object, elf_file: *Elf) void {
504 const first_global = self.first_global orelse return;488 const first_global = self.first_global orelse return;
505 for (self.globals(), 0..) |index, i| {489 for (self.globals(), 0..) |index, i| {
506 const sym_idx = first_global + i;490 const sym_idx = first_global + i;
507 const sym = self.symtab[sym_idx];491 const sym = self.symtab.items[sym_idx];
508 if (sym.st_bind() == elf.STB_WEAK) continue;492 if (sym.st_bind() == elf.STB_WEAK) continue;
509493
510 const global = elf_file.symbol(index);494 const global = elf_file.symbol(index);
...@@ -531,7 +515,7 @@ pub fn checkDuplicates(self: *Object, elf_file: *Elf) void {...@@ -531,7 +515,7 @@ pub fn checkDuplicates(self: *Object, elf_file: *Elf) void {
531 const first_global = self.first_global orelse return;515 const first_global = self.first_global orelse return;
532 for (self.globals(), 0..) |index, i| {516 for (self.globals(), 0..) |index, i| {
533 const sym_idx = @as(u32, @intCast(first_global + i));517 const sym_idx = @as(u32, @intCast(first_global + i));
534 const this_sym = self.symtab[sym_idx];518 const this_sym = self.symtab.items[sym_idx];
535 const global = elf_file.symbol(index);519 const global = elf_file.symbol(index);
536 const global_file = global.getFile(elf_file) orelse continue;520 const global_file = global.getFile(elf_file) orelse continue;
537521
...@@ -560,7 +544,7 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {...@@ -560,7 +544,7 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {
560 const first_global = self.first_global orelse return;544 const first_global = self.first_global orelse return;
561 for (self.globals(), 0..) |index, i| {545 for (self.globals(), 0..) |index, i| {
562 const sym_idx = @as(u32, @intCast(first_global + i));546 const sym_idx = @as(u32, @intCast(first_global + i));
563 const this_sym = self.symtab[sym_idx];547 const this_sym = self.symtab.items[sym_idx];
564 if (this_sym.st_shndx != elf.SHN_COMMON) continue;548 if (this_sym.st_shndx != elf.SHN_COMMON) continue;
565549
566 const global = elf_file.symbol(index);550 const global = elf_file.symbol(index);
...@@ -584,8 +568,10 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {...@@ -584,8 +568,10 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {
584 const name = if (is_tls) ".tls_common" else ".common";568 const name = if (is_tls) ".tls_common" else ".common";
585569
586 const atom = elf_file.atom(atom_index).?;570 const atom = elf_file.atom(atom_index).?;
571 const name_offset = @as(u32, @intCast(self.strtab.items.len));
572 try self.strtab.writer(gpa).print("{s}\x00", .{name});
587 atom.atom_index = atom_index;573 atom.atom_index = atom_index;
588 atom.name_offset = try elf_file.strtab.insert(gpa, name);574 atom.name_offset = name_offset;
589 atom.file_index = self.index;575 atom.file_index = self.index;
590 atom.size = this_sym.st_size;576 atom.size = this_sym.st_size;
591 const alignment = this_sym.st_value;577 const alignment = this_sym.st_value;
...@@ -597,7 +583,7 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {...@@ -597,7 +583,7 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {
597 const shdr = try self.shdrs.addOne(gpa);583 const shdr = try self.shdrs.addOne(gpa);
598 const sh_size = math.cast(usize, this_sym.st_size) orelse return error.Overflow;584 const sh_size = math.cast(usize, this_sym.st_size) orelse return error.Overflow;
599 shdr.* = .{585 shdr.* = .{
600 .sh_name = try self.strings.insert(gpa, name),586 .sh_name = name_offset,
601 .sh_type = elf.SHT_NOBITS,587 .sh_type = elf.SHT_NOBITS,
602 .sh_flags = sh_flags,588 .sh_flags = sh_flags,
603 .sh_addr = 0,589 .sh_addr = 0,
...@@ -665,56 +651,6 @@ pub fn allocateAtoms(self: Object, elf_file: *Elf) void {...@@ -665,56 +651,6 @@ pub fn allocateAtoms(self: Object, elf_file: *Elf) void {
665 }651 }
666}652}
667653
668pub fn updateSymtabSize(self: *Object, elf_file: *Elf) void {
669 for (self.locals()) |local_index| {
670 const local = elf_file.symbol(local_index);
671 if (local.atom(elf_file)) |atom| if (!atom.flags.alive) continue;
672 const esym = local.elfSym(elf_file);
673 switch (esym.st_type()) {
674 elf.STT_SECTION, elf.STT_NOTYPE => continue,
675 else => {},
676 }
677 local.flags.output_symtab = true;
678 self.output_symtab_size.nlocals += 1;
679 }
680
681 for (self.globals()) |global_index| {
682 const global = elf_file.symbol(global_index);
683 if (global.file(elf_file)) |file| if (file.index() != self.index) continue;
684 if (global.atom(elf_file)) |atom| if (!atom.flags.alive) continue;
685 global.flags.output_symtab = true;
686 if (global.isLocal()) {
687 self.output_symtab_size.nlocals += 1;
688 } else {
689 self.output_symtab_size.nglobals += 1;
690 }
691 }
692}
693
694pub fn writeSymtab(self: *Object, elf_file: *Elf, ctx: anytype) void {
695 var ilocal = ctx.ilocal;
696 for (self.locals()) |local_index| {
697 const local = elf_file.symbol(local_index);
698 if (!local.flags.output_symtab) continue;
699 local.setOutputSym(elf_file, &ctx.symtab[ilocal]);
700 ilocal += 1;
701 }
702
703 var iglobal = ctx.iglobal;
704 for (self.globals()) |global_index| {
705 const global = elf_file.symbol(global_index);
706 if (global.file(elf_file)) |file| if (file.index() != self.index) continue;
707 if (!global.flags.output_symtab) continue;
708 if (global.isLocal()) {
709 global.setOutputSym(elf_file, &ctx.symtab[ilocal]);
710 ilocal += 1;
711 } else {
712 global.setOutputSym(elf_file, &ctx.symtab[iglobal]);
713 iglobal += 1;
714 }
715 }
716}
717
718pub fn locals(self: Object) []const Symbol.Index {654pub fn locals(self: Object) []const Symbol.Index {
719 const end = self.first_global orelse self.symbols.items.len;655 const end = self.first_global orelse self.symbols.items.len;
720 return self.symbols.items[0..end];656 return self.symbols.items[0..end];
...@@ -760,11 +696,6 @@ pub fn codeDecompressAlloc(self: Object, elf_file: *Elf, atom_index: Atom.Index)...@@ -760,11 +696,6 @@ pub fn codeDecompressAlloc(self: Object, elf_file: *Elf, atom_index: Atom.Index)
760 } else return gpa.dupe(u8, data);696 } else return gpa.dupe(u8, data);
761}697}
762698
763fn getString(self: *Object, off: u32) [:0]const u8 {
764 assert(off < self.strtab.len);
765 return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.ptr + off)), 0);
766}
767
768pub fn comdatGroupMembers(self: *Object, index: u16) []align(1) const u32 {699pub fn comdatGroupMembers(self: *Object, index: u16) []align(1) const u32 {
769 const raw = self.shdrContents(index);700 const raw = self.shdrContents(index);
770 const nmembers = @divExact(raw.len, @sizeOf(u32));701 const nmembers = @divExact(raw.len, @sizeOf(u32));
...@@ -782,6 +713,11 @@ pub fn getRelocs(self: *Object, shndx: u32) []align(1) const elf.Elf64_Rela {...@@ -782,6 +713,11 @@ pub fn getRelocs(self: *Object, shndx: u32) []align(1) const elf.Elf64_Rela {
782 return @as([*]align(1) const elf.Elf64_Rela, @ptrCast(raw.ptr))[0..num];713 return @as([*]align(1) const elf.Elf64_Rela, @ptrCast(raw.ptr))[0..num];
783}714}
784715
716pub fn getString(self: Object, off: u32) [:0]const u8 {
717 assert(off < self.strtab.items.len);
718 return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0);
719}
720
785pub fn format(721pub fn format(
786 self: *Object,722 self: *Object,
787 comptime unused_fmt_string: []const u8,723 comptime unused_fmt_string: []const u8,
...@@ -991,6 +927,5 @@ const Cie = eh_frame.Cie;...@@ -991,6 +927,5 @@ const Cie = eh_frame.Cie;
991const Elf = @import("../Elf.zig");927const Elf = @import("../Elf.zig");
992const Fde = eh_frame.Fde;928const Fde = eh_frame.Fde;
993const File = @import("file.zig").File;929const File = @import("file.zig").File;
994const StringTable = @import("../strtab.zig").StringTable;
995const Symbol = @import("Symbol.zig");930const Symbol = @import("Symbol.zig");
996const Alignment = Atom.Alignment;931const Alignment = Atom.Alignment;
src/link/Elf/SharedObject.zig+50-62
...@@ -4,19 +4,20 @@ index: File.Index,...@@ -4,19 +4,20 @@ index: File.Index,
44
5header: ?elf.Elf64_Ehdr = null,5header: ?elf.Elf64_Ehdr = null,
6shdrs: std.ArrayListUnmanaged(ElfShdr) = .{},6shdrs: std.ArrayListUnmanaged(ElfShdr) = .{},
7symtab: []align(1) const elf.Elf64_Sym = &[0]elf.Elf64_Sym{},7
8strtab: []const u8 = &[0]u8{},8symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
9strtab: std.ArrayListUnmanaged(u8) = .{},
9/// Version symtab contains version strings of the symbols if present.10/// Version symtab contains version strings of the symbols if present.
10versyms: std.ArrayListUnmanaged(elf.Elf64_Versym) = .{},11versyms: std.ArrayListUnmanaged(elf.Elf64_Versym) = .{},
11verstrings: std.ArrayListUnmanaged(u32) = .{},12verstrings: std.ArrayListUnmanaged(u32) = .{},
13symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
14aliases: ?std.ArrayListUnmanaged(u32) = null,
1215
16dynsym_sect_index: ?u16 = null,
13dynamic_sect_index: ?u16 = null,17dynamic_sect_index: ?u16 = null,
14versym_sect_index: ?u16 = null,18versym_sect_index: ?u16 = null,
15verdef_sect_index: ?u16 = null,19verdef_sect_index: ?u16 = null,
1620
17symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
18aliases: ?std.ArrayListUnmanaged(u32) = null,
19
20needed: bool,21needed: bool,
21alive: bool,22alive: bool,
2223
...@@ -36,6 +37,8 @@ pub fn isSharedObject(path: []const u8) !bool {...@@ -36,6 +37,8 @@ pub fn isSharedObject(path: []const u8) !bool {
36pub fn deinit(self: *SharedObject, allocator: Allocator) void {37pub fn deinit(self: *SharedObject, allocator: Allocator) void {
37 allocator.free(self.path);38 allocator.free(self.path);
38 allocator.free(self.data);39 allocator.free(self.data);
40 self.symtab.deinit(allocator);
41 self.strtab.deinit(allocator);
39 self.versyms.deinit(allocator);42 self.versyms.deinit(allocator);
40 self.verstrings.deinit(allocator);43 self.verstrings.deinit(allocator);
41 self.symbols.deinit(allocator);44 self.symbols.deinit(allocator);
...@@ -51,7 +54,6 @@ pub fn parse(self: *SharedObject, elf_file: *Elf) !void {...@@ -51,7 +54,6 @@ pub fn parse(self: *SharedObject, elf_file: *Elf) !void {
51 self.header = try reader.readStruct(elf.Elf64_Ehdr);54 self.header = try reader.readStruct(elf.Elf64_Ehdr);
52 const shoff = std.math.cast(usize, self.header.?.e_shoff) orelse return error.Overflow;55 const shoff = std.math.cast(usize, self.header.?.e_shoff) orelse return error.Overflow;
5356
54 var dynsym_index: ?u16 = null;
55 const shdrs = @as(57 const shdrs = @as(
56 [*]align(1) const elf.Elf64_Shdr,58 [*]align(1) const elf.Elf64_Shdr,
57 @ptrCast(self.data.ptr + shoff),59 @ptrCast(self.data.ptr + shoff),
...@@ -61,7 +63,7 @@ pub fn parse(self: *SharedObject, elf_file: *Elf) !void {...@@ -61,7 +63,7 @@ pub fn parse(self: *SharedObject, elf_file: *Elf) !void {
61 for (shdrs, 0..) |shdr, i| {63 for (shdrs, 0..) |shdr, i| {
62 self.shdrs.appendAssumeCapacity(try ElfShdr.fromElf64Shdr(shdr));64 self.shdrs.appendAssumeCapacity(try ElfShdr.fromElf64Shdr(shdr));
63 switch (shdr.sh_type) {65 switch (shdr.sh_type) {
64 elf.SHT_DYNSYM => dynsym_index = @as(u16, @intCast(i)),66 elf.SHT_DYNSYM => self.dynsym_sect_index = @as(u16, @intCast(i)),
65 elf.SHT_DYNAMIC => self.dynamic_sect_index = @as(u16, @intCast(i)),67 elf.SHT_DYNAMIC => self.dynamic_sect_index = @as(u16, @intCast(i)),
66 elf.SHT_GNU_VERSYM => self.versym_sect_index = @as(u16, @intCast(i)),68 elf.SHT_GNU_VERSYM => self.versym_sect_index = @as(u16, @intCast(i)),
67 elf.SHT_GNU_VERDEF => self.verdef_sect_index = @as(u16, @intCast(i)),69 elf.SHT_GNU_VERDEF => self.verdef_sect_index = @as(u16, @intCast(i)),
...@@ -69,20 +71,13 @@ pub fn parse(self: *SharedObject, elf_file: *Elf) !void {...@@ -69,20 +71,13 @@ pub fn parse(self: *SharedObject, elf_file: *Elf) !void {
69 }71 }
70 }72 }
7173
72 if (dynsym_index) |index| {
73 const shdr = self.shdrs.items[index];
74 const symtab = self.shdrContents(index);
75 const nsyms = @divExact(symtab.len, @sizeOf(elf.Elf64_Sym));
76 self.symtab = @as([*]align(1) const elf.Elf64_Sym, @ptrCast(symtab.ptr))[0..nsyms];
77 self.strtab = self.shdrContents(@as(u16, @intCast(shdr.sh_link)));
78 }
79
80 try self.parseVersions(elf_file);74 try self.parseVersions(elf_file);
81 try self.initSymtab(elf_file);75 try self.initSymtab(elf_file);
82}76}
8377
84fn parseVersions(self: *SharedObject, elf_file: *Elf) !void {78fn parseVersions(self: *SharedObject, elf_file: *Elf) !void {
85 const gpa = elf_file.base.allocator;79 const gpa = elf_file.base.allocator;
80 const symtab = self.getSymtabRaw();
8681
87 try self.verstrings.resize(gpa, 2);82 try self.verstrings.resize(gpa, 2);
88 self.verstrings.items[elf.VER_NDX_LOCAL] = 0;83 self.verstrings.items[elf.VER_NDX_LOCAL] = 0;
...@@ -107,7 +102,7 @@ fn parseVersions(self: *SharedObject, elf_file: *Elf) !void {...@@ -107,7 +102,7 @@ fn parseVersions(self: *SharedObject, elf_file: *Elf) !void {
107 }102 }
108 }103 }
109104
110 try self.versyms.ensureTotalCapacityPrecise(gpa, self.symtab.len);105 try self.versyms.ensureTotalCapacityPrecise(gpa, symtab.len);
111106
112 if (self.versym_sect_index) |shndx| {107 if (self.versym_sect_index) |shndx| {
113 const versyms_raw = self.shdrContents(shndx);108 const versyms_raw = self.shdrContents(shndx);
...@@ -120,30 +115,39 @@ fn parseVersions(self: *SharedObject, elf_file: *Elf) !void {...@@ -120,30 +115,39 @@ fn parseVersions(self: *SharedObject, elf_file: *Elf) !void {
120 ver;115 ver;
121 self.versyms.appendAssumeCapacity(normalized_ver);116 self.versyms.appendAssumeCapacity(normalized_ver);
122 }117 }
123 } else for (0..self.symtab.len) |_| {118 } else for (0..symtab.len) |_| {
124 self.versyms.appendAssumeCapacity(elf.VER_NDX_GLOBAL);119 self.versyms.appendAssumeCapacity(elf.VER_NDX_GLOBAL);
125 }120 }
126}121}
127122
128fn initSymtab(self: *SharedObject, elf_file: *Elf) !void {123fn initSymtab(self: *SharedObject, elf_file: *Elf) !void {
129 const gpa = elf_file.base.allocator;124 const gpa = elf_file.base.allocator;
125 const symtab = self.getSymtabRaw();
126 const strtab = self.getStrtabRaw();
130127
131 try self.symbols.ensureTotalCapacityPrecise(gpa, self.symtab.len);128 try self.strtab.appendSlice(gpa, strtab);
129 try self.symtab.ensureTotalCapacityPrecise(gpa, symtab.len);
130 try self.symbols.ensureTotalCapacityPrecise(gpa, symtab.len);
132131
133 for (self.symtab, 0..) |sym, i| {132 for (symtab, 0..) |sym, i| {
134 const hidden = self.versyms.items[i] & elf.VERSYM_HIDDEN != 0;133 const hidden = self.versyms.items[i] & elf.VERSYM_HIDDEN != 0;
135 const name = self.getString(sym.st_name);134 const name = self.getString(sym.st_name);
136 // We need to garble up the name so that we don't pick this symbol135 // We need to garble up the name so that we don't pick this symbol
137 // during symbol resolution. Thank you GNU!136 // during symbol resolution. Thank you GNU!
138 const off = if (hidden) blk: {137 const name_off = if (hidden) blk: {
139 const full_name = try std.fmt.allocPrint(gpa, "{s}@{s}", .{138 const mangled = try std.fmt.allocPrint(gpa, "{s}@{s}", .{
140 name,139 name,
141 self.versionString(self.versyms.items[i]),140 self.versionString(self.versyms.items[i]),
142 });141 });
143 defer gpa.free(full_name);142 defer gpa.free(mangled);
144 break :blk try elf_file.strtab.insert(gpa, full_name);143 const name_off = @as(u32, @intCast(self.strtab.items.len));
145 } else try elf_file.strtab.insert(gpa, name);144 try self.strtab.writer(gpa).print("{s}\x00", .{mangled});
146 const gop = try elf_file.getOrPutGlobal(off);145 break :blk name_off;
146 } else sym.st_name;
147 const out_sym = self.symtab.addOneAssumeCapacity();
148 out_sym.* = sym;
149 out_sym.st_name = name_off;
150 const gop = try elf_file.getOrPutGlobal(self.getString(name_off));
147 self.symbols.addOneAssumeCapacity().* = gop.index;151 self.symbols.addOneAssumeCapacity().* = gop.index;
148 }152 }
149}153}
...@@ -151,7 +155,7 @@ fn initSymtab(self: *SharedObject, elf_file: *Elf) !void {...@@ -151,7 +155,7 @@ fn initSymtab(self: *SharedObject, elf_file: *Elf) !void {
151pub fn resolveSymbols(self: *SharedObject, elf_file: *Elf) void {155pub fn resolveSymbols(self: *SharedObject, elf_file: *Elf) void {
152 for (self.globals(), 0..) |index, i| {156 for (self.globals(), 0..) |index, i| {
153 const esym_index = @as(u32, @intCast(i));157 const esym_index = @as(u32, @intCast(i));
154 const this_sym = self.symtab[esym_index];158 const this_sym = self.symtab.items[esym_index];
155159
156 if (this_sym.st_shndx == elf.SHN_UNDEF) continue;160 if (this_sym.st_shndx == elf.SHN_UNDEF) continue;
157161
...@@ -166,18 +170,9 @@ pub fn resolveSymbols(self: *SharedObject, elf_file: *Elf) void {...@@ -166,18 +170,9 @@ pub fn resolveSymbols(self: *SharedObject, elf_file: *Elf) void {
166 }170 }
167}171}
168172
169pub fn resetGlobals(self: *SharedObject, elf_file: *Elf) void {
170 for (self.globals()) |index| {
171 const global = elf_file.symbol(index);
172 const off = global.name_offset;
173 global.* = .{};
174 global.name_offset = off;
175 }
176}
177
178pub fn markLive(self: *SharedObject, elf_file: *Elf) void {173pub fn markLive(self: *SharedObject, elf_file: *Elf) void {
179 for (self.globals(), 0..) |index, i| {174 for (self.globals(), 0..) |index, i| {
180 const sym = self.symtab[i];175 const sym = self.symtab.items[i];
181 if (sym.st_shndx != elf.SHN_UNDEF) continue;176 if (sym.st_shndx != elf.SHN_UNDEF) continue;
182177
183 const global = elf_file.symbol(index);178 const global = elf_file.symbol(index);
...@@ -193,27 +188,6 @@ pub fn markLive(self: *SharedObject, elf_file: *Elf) void {...@@ -193,27 +188,6 @@ pub fn markLive(self: *SharedObject, elf_file: *Elf) void {
193 }188 }
194}189}
195190
196pub fn updateSymtabSize(self: *SharedObject, elf_file: *Elf) void {
197 for (self.globals()) |global_index| {
198 const global = elf_file.symbol(global_index);
199 if (global.file(elf_file)) |file| if (file.index() != self.index) continue;
200 if (global.isLocal()) continue;
201 global.flags.output_symtab = true;
202 self.output_symtab_size.nglobals += 1;
203 }
204}
205
206pub fn writeSymtab(self: *SharedObject, elf_file: *Elf, ctx: anytype) void {
207 var iglobal = ctx.iglobal;
208 for (self.globals()) |global_index| {
209 const global = elf_file.symbol(global_index);
210 if (global.file(elf_file)) |file| if (file.index() != self.index) continue;
211 if (!global.flags.output_symtab) continue;
212 global.setOutputSym(elf_file, &ctx.symtab[iglobal]);
213 iglobal += 1;
214 }
215}
216
217pub fn globals(self: SharedObject) []const Symbol.Index {191pub fn globals(self: SharedObject) []const Symbol.Index {
218 return self.symbols.items;192 return self.symbols.items;
219}193}
...@@ -223,11 +197,6 @@ pub fn shdrContents(self: SharedObject, index: u16) []const u8 {...@@ -223,11 +197,6 @@ pub fn shdrContents(self: SharedObject, index: u16) []const u8 {
223 return self.data[shdr.sh_offset..][0..shdr.sh_size];197 return self.data[shdr.sh_offset..][0..shdr.sh_size];
224}198}
225199
226pub fn getString(self: SharedObject, off: u32) [:0]const u8 {
227 assert(off < self.strtab.len);
228 return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.ptr + off)), 0);
229}
230
231pub fn versionString(self: SharedObject, index: elf.Elf64_Versym) [:0]const u8 {200pub fn versionString(self: SharedObject, index: elf.Elf64_Versym) [:0]const u8 {
232 const off = self.verstrings.items[index & elf.VERSYM_VERSION];201 const off = self.verstrings.items[index & elf.VERSYM_VERSION];
233 return self.getString(off);202 return self.getString(off);
...@@ -309,6 +278,25 @@ pub fn symbolAliases(self: *SharedObject, index: u32, elf_file: *Elf) []const u3...@@ -309,6 +278,25 @@ pub fn symbolAliases(self: *SharedObject, index: u32, elf_file: *Elf) []const u3
309 return aliases.items[start..end];278 return aliases.items[start..end];
310}279}
311280
281pub fn getString(self: SharedObject, off: u32) [:0]const u8 {
282 assert(off < self.strtab.items.len);
283 return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0);
284}
285
286pub fn getSymtabRaw(self: SharedObject) []align(1) const elf.Elf64_Sym {
287 const index = self.dynsym_sect_index orelse return &[0]elf.Elf64_Sym{};
288 const raw_symtab = self.shdrContents(index);
289 const nsyms = @divExact(raw_symtab.len, @sizeOf(elf.Elf64_Sym));
290 const symtab = @as([*]align(1) const elf.Elf64_Sym, @ptrCast(raw_symtab.ptr))[0..nsyms];
291 return symtab;
292}
293
294pub fn getStrtabRaw(self: SharedObject) []const u8 {
295 const index = self.dynsym_sect_index orelse return &[0]u8{};
296 const shdr = self.shdrs.items[index];
297 return self.shdrContents(@as(u16, @intCast(shdr.sh_link)));
298}
299
312pub fn format(300pub fn format(
313 self: SharedObject,301 self: SharedObject,
314 comptime unused_fmt_string: []const u8,302 comptime unused_fmt_string: []const u8,
src/link/Elf/Symbol.zig+29-20
...@@ -42,7 +42,8 @@ pub fn outputShndx(symbol: Symbol) ?u16 {...@@ -42,7 +42,8 @@ pub fn outputShndx(symbol: Symbol) ?u16 {
42 return symbol.output_section_index;42 return symbol.output_section_index;
43}43}
4444
45pub fn isLocal(symbol: Symbol) bool {45pub fn isLocal(symbol: Symbol, elf_file: *Elf) bool {
46 if (elf_file.isRelocatable()) return symbol.elfSym(elf_file).st_bind() == elf.STB_LOCAL;
46 return !(symbol.flags.import or symbol.flags.@"export");47 return !(symbol.flags.import or symbol.flags.@"export");
47}48}
4849
...@@ -58,7 +59,11 @@ pub fn @"type"(symbol: Symbol, elf_file: *Elf) u4 {...@@ -58,7 +59,11 @@ pub fn @"type"(symbol: Symbol, elf_file: *Elf) u4 {
58}59}
5960
60pub fn name(symbol: Symbol, elf_file: *Elf) [:0]const u8 {61pub fn name(symbol: Symbol, elf_file: *Elf) [:0]const u8 {
61 return elf_file.strtab.getAssumeExists(symbol.name_offset);62 if (symbol.flags.global) return elf_file.strings.getAssumeExists(symbol.name_offset);
63 const file_ptr = symbol.file(elf_file).?;
64 return switch (file_ptr) {
65 inline else => |x| x.getString(symbol.name_offset),
66 };
62}67}
6368
64pub fn atom(symbol: Symbol, elf_file: *Elf) ?*Atom {69pub fn atom(symbol: Symbol, elf_file: *Elf) ?*Atom {
...@@ -71,11 +76,10 @@ pub fn file(symbol: Symbol, elf_file: *Elf) ?File {...@@ -71,11 +76,10 @@ pub fn file(symbol: Symbol, elf_file: *Elf) ?File {
7176
72pub fn elfSym(symbol: Symbol, elf_file: *Elf) elf.Elf64_Sym {77pub fn elfSym(symbol: Symbol, elf_file: *Elf) elf.Elf64_Sym {
73 const file_ptr = symbol.file(elf_file).?;78 const file_ptr = symbol.file(elf_file).?;
74 switch (file_ptr) {79 return switch (file_ptr) {
75 .zig_object => |x| return x.elfSym(symbol.esym_index).*,80 .zig_object => |x| x.elfSym(symbol.esym_index).*,
76 .linker_defined => |x| return x.symtab.items[symbol.esym_index],81 inline else => |x| x.symtab.items[symbol.esym_index],
77 inline else => |x| return x.symtab[symbol.esym_index],82 };
78 }
79}83}
8084
81pub fn symbolRank(symbol: Symbol, elf_file: *Elf) u32 {85pub fn symbolRank(symbol: Symbol, elf_file: *Elf) u32 {
...@@ -164,6 +168,8 @@ const GetOrCreateZigGotEntryResult = struct {...@@ -164,6 +168,8 @@ const GetOrCreateZigGotEntryResult = struct {
164};168};
165169
166pub fn getOrCreateZigGotEntry(symbol: *Symbol, symbol_index: Index, elf_file: *Elf) !GetOrCreateZigGotEntryResult {170pub fn getOrCreateZigGotEntry(symbol: *Symbol, symbol_index: Index, elf_file: *Elf) !GetOrCreateZigGotEntryResult {
171 assert(!elf_file.isRelocatable());
172 assert(symbol.flags.needs_zig_got);
167 if (symbol.flags.has_zig_got) return .{ .found_existing = true, .index = symbol.extra(elf_file).?.zig_got };173 if (symbol.flags.has_zig_got) return .{ .found_existing = true, .index = symbol.extra(elf_file).?.zig_got };
168 const index = try elf_file.zig_got.addSymbol(symbol_index, elf_file);174 const index = try elf_file.zig_got.addSymbol(symbol_index, elf_file);
169 return .{ .found_existing = false, .index = index };175 return .{ .found_existing = false, .index = index };
...@@ -201,14 +207,11 @@ pub fn setExtra(symbol: Symbol, extras: Extra, elf_file: *Elf) void {...@@ -201,14 +207,11 @@ pub fn setExtra(symbol: Symbol, extras: Extra, elf_file: *Elf) void {
201}207}
202208
203pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {209pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {
204 const file_ptr = symbol.file(elf_file) orelse {210 const file_ptr = symbol.file(elf_file).?;
205 out.* = Elf.null_sym;
206 return;
207 };
208 const esym = symbol.elfSym(elf_file);211 const esym = symbol.elfSym(elf_file);
209 const st_type = symbol.type(elf_file);212 const st_type = symbol.type(elf_file);
210 const st_bind: u8 = blk: {213 const st_bind: u8 = blk: {
211 if (symbol.isLocal()) break :blk 0;214 if (symbol.isLocal(elf_file)) break :blk 0;
212 if (symbol.flags.weak) break :blk elf.STB_WEAK;215 if (symbol.flags.weak) break :blk elf.STB_WEAK;
213 if (file_ptr == .shared_object) break :blk elf.STB_GLOBAL;216 if (file_ptr == .shared_object) break :blk elf.STB_GLOBAL;
214 break :blk esym.st_bind();217 break :blk esym.st_bind();
...@@ -216,6 +219,8 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {...@@ -216,6 +219,8 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {
216 const st_shndx = blk: {219 const st_shndx = blk: {
217 if (symbol.flags.has_copy_rel) break :blk elf_file.copy_rel_section_index.?;220 if (symbol.flags.has_copy_rel) break :blk elf_file.copy_rel_section_index.?;
218 if (file_ptr == .shared_object or esym.st_shndx == elf.SHN_UNDEF) break :blk elf.SHN_UNDEF;221 if (file_ptr == .shared_object or esym.st_shndx == elf.SHN_UNDEF) break :blk elf.SHN_UNDEF;
222 // TODO I think this is wrong and obsolete
223 if (elf_file.isRelocatable() and st_type == elf.STT_SECTION) break :blk symbol.outputShndx().?;
219 if (symbol.atom(elf_file) == null and file_ptr != .linker_defined)224 if (symbol.atom(elf_file) == null and file_ptr != .linker_defined)
220 break :blk elf.SHN_ABS;225 break :blk elf.SHN_ABS;
221 break :blk symbol.outputShndx() orelse elf.SHN_UNDEF;226 break :blk symbol.outputShndx() orelse elf.SHN_UNDEF;
...@@ -232,14 +237,11 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {...@@ -232,14 +237,11 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {
232 break :blk symbol.value - elf_file.tlsAddress();237 break :blk symbol.value - elf_file.tlsAddress();
233 break :blk symbol.value;238 break :blk symbol.value;
234 };239 };
235 out.* = .{240 out.st_info = (st_bind << 4) | st_type;
236 .st_name = symbol.name_offset,241 out.st_other = esym.st_other;
237 .st_info = (st_bind << 4) | st_type,242 out.st_shndx = st_shndx;
238 .st_other = esym.st_other,243 out.st_value = st_value;
239 .st_shndx = st_shndx,244 out.st_size = esym.st_size;
240 .st_value = st_value,
241 .st_size = esym.st_size,
242 };
243}245}
244246
245pub fn format(247pub fn format(
...@@ -340,6 +342,12 @@ pub const Flags = packed struct {...@@ -340,6 +342,12 @@ pub const Flags = packed struct {
340 /// Whether this symbol is weak.342 /// Whether this symbol is weak.
341 weak: bool = false,343 weak: bool = false,
342344
345 /// Whether the symbol has its name interned in global symbol
346 /// resolver table.
347 /// This happens for any symbol that is considered a global
348 /// symbol, but is not necessarily an import or export.
349 global: bool = false,
350
343 /// Whether the symbol makes into the output symtab.351 /// Whether the symbol makes into the output symtab.
344 output_symtab: bool = false,352 output_symtab: bool = false,
345353
...@@ -373,6 +381,7 @@ pub const Flags = packed struct {...@@ -373,6 +381,7 @@ pub const Flags = packed struct {
373 has_tlsdesc: bool = false,381 has_tlsdesc: bool = false,
374382
375 /// Whether the symbol contains .zig.got indirection.383 /// Whether the symbol contains .zig.got indirection.
384 needs_zig_got: bool = false,
376 has_zig_got: bool = false,385 has_zig_got: bool = false,
377};386};
378387
src/link/Elf/ZigObject.zig+305-105
...@@ -9,6 +9,7 @@ index: File.Index,...@@ -9,6 +9,7 @@ index: File.Index,
99
10local_esyms: std.MultiArrayList(ElfSym) = .{},10local_esyms: std.MultiArrayList(ElfSym) = .{},
11global_esyms: std.MultiArrayList(ElfSym) = .{},11global_esyms: std.MultiArrayList(ElfSym) = .{},
12strtab: StringTable = .{},
12local_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},13local_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
13global_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},14global_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
14globals_lookup: std.AutoHashMapUnmanaged(u32, Symbol.Index) = .{},15globals_lookup: std.AutoHashMapUnmanaged(u32, Symbol.Index) = .{},
...@@ -19,6 +20,7 @@ relocs: std.ArrayListUnmanaged(std.ArrayListUnmanaged(elf.Elf64_Rela)) = .{},...@@ -19,6 +20,7 @@ relocs: std.ArrayListUnmanaged(std.ArrayListUnmanaged(elf.Elf64_Rela)) = .{},
19num_dynrelocs: u32 = 0,20num_dynrelocs: u32 = 0,
2021
21output_symtab_size: Elf.SymtabSize = .{},22output_symtab_size: Elf.SymtabSize = .{},
23output_ar_state: Archive.ArState = .{},
2224
23dwarf: ?Dwarf = null,25dwarf: ?Dwarf = null,
2426
...@@ -74,8 +76,9 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void {...@@ -74,8 +76,9 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void {
74 const gpa = elf_file.base.allocator;76 const gpa = elf_file.base.allocator;
7577
76 try self.atoms.append(gpa, 0); // null input section78 try self.atoms.append(gpa, 0); // null input section
79 try self.strtab.buffer.append(gpa, 0);
7780
78 const name_off = try elf_file.strtab.insert(gpa, std.fs.path.stem(self.path));81 const name_off = try self.strtab.insert(gpa, std.fs.path.stem(self.path));
79 const symbol_index = try elf_file.addSymbol();82 const symbol_index = try elf_file.addSymbol();
80 try self.local_symbols.append(gpa, symbol_index);83 try self.local_symbols.append(gpa, symbol_index);
81 const symbol_ptr = elf_file.symbol(symbol_index);84 const symbol_ptr = elf_file.symbol(symbol_index);
...@@ -85,7 +88,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void {...@@ -85,7 +88,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void {
85 const esym_index = try self.addLocalEsym(gpa);88 const esym_index = try self.addLocalEsym(gpa);
86 const esym = &self.local_esyms.items(.elf_sym)[esym_index];89 const esym = &self.local_esyms.items(.elf_sym)[esym_index];
87 esym.st_name = name_off;90 esym.st_name = name_off;
88 esym.st_info |= elf.STT_FILE;91 esym.st_info = elf.STT_FILE;
89 esym.st_shndx = elf.SHN_ABS;92 esym.st_shndx = elf.SHN_ABS;
90 symbol_ptr.esym_index = esym_index;93 symbol_ptr.esym_index = esym_index;
9194
...@@ -97,6 +100,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void {...@@ -97,6 +100,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void {
97pub fn deinit(self: *ZigObject, allocator: Allocator) void {100pub fn deinit(self: *ZigObject, allocator: Allocator) void {
98 self.local_esyms.deinit(allocator);101 self.local_esyms.deinit(allocator);
99 self.global_esyms.deinit(allocator);102 self.global_esyms.deinit(allocator);
103 self.strtab.deinit(allocator);
100 self.local_symbols.deinit(allocator);104 self.local_symbols.deinit(allocator);
101 self.global_symbols.deinit(allocator);105 self.global_symbols.deinit(allocator);
102 self.globals_lookup.deinit(allocator);106 self.globals_lookup.deinit(allocator);
...@@ -177,16 +181,16 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf) !void {...@@ -177,16 +181,16 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf) !void {
177 }181 }
178182
179 if (self.debug_info_header_dirty) {183 if (self.debug_info_header_dirty) {
180 const text_phdr = &elf_file.phdrs.items[elf_file.phdr_zig_load_re_index.?];184 const text_shdr = elf_file.shdrs.items[elf_file.zig_text_section_index.?];
181 const low_pc = text_phdr.p_vaddr;185 const low_pc = text_shdr.sh_addr;
182 const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz;186 const high_pc = text_shdr.sh_addr + text_shdr.sh_size;
183 try dw.writeDbgInfoHeader(elf_file.base.options.module.?, low_pc, high_pc);187 try dw.writeDbgInfoHeader(elf_file.base.options.module.?, low_pc, high_pc);
184 self.debug_info_header_dirty = false;188 self.debug_info_header_dirty = false;
185 }189 }
186190
187 if (self.debug_aranges_section_dirty) {191 if (self.debug_aranges_section_dirty) {
188 const text_phdr = &elf_file.phdrs.items[elf_file.phdr_zig_load_re_index.?];192 const text_shdr = elf_file.shdrs.items[elf_file.zig_text_section_index.?];
189 try dw.writeDbgAranges(text_phdr.p_vaddr, text_phdr.p_memsz);193 try dw.writeDbgAranges(text_shdr.sh_addr, text_shdr.sh_size);
190 self.debug_aranges_section_dirty = false;194 self.debug_aranges_section_dirty = false;
191 }195 }
192196
...@@ -207,6 +211,8 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf) !void {...@@ -207,6 +211,8 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf) !void {
207 self.saveDebugSectionsSizes(elf_file);211 self.saveDebugSectionsSizes(elf_file);
208 }212 }
209213
214 try self.sortSymbols(elf_file);
215
210 // The point of flushModule() is to commit changes, so in theory, nothing should216 // The point of flushModule() is to commit changes, so in theory, nothing should
211 // be dirty after this. However, it is possible for some things to remain217 // be dirty after this. However, it is possible for some things to remain
212 // dirty because they fail to be written in the event of compile errors,218 // dirty because they fail to be written in the event of compile errors,
...@@ -281,6 +287,22 @@ pub fn addAtom(self: *ZigObject, elf_file: *Elf) !Symbol.Index {...@@ -281,6 +287,22 @@ pub fn addAtom(self: *ZigObject, elf_file: *Elf) !Symbol.Index {
281 return symbol_index;287 return symbol_index;
282}288}
283289
290pub fn addSectionSymbol(self: *ZigObject, shndx: u16, elf_file: *Elf) !void {
291 assert(elf_file.isRelocatable());
292 const gpa = elf_file.base.allocator;
293 const symbol_index = try elf_file.addSymbol();
294 try self.local_symbols.append(gpa, symbol_index);
295 const symbol_ptr = elf_file.symbol(symbol_index);
296 symbol_ptr.file_index = self.index;
297 symbol_ptr.output_section_index = shndx;
298
299 const esym_index = try self.addLocalEsym(gpa);
300 const esym = &self.local_esyms.items(.elf_sym)[esym_index];
301 esym.st_info = elf.STT_SECTION;
302 esym.st_shndx = shndx;
303 symbol_ptr.esym_index = esym_index;
304}
305
284/// TODO actually create fake input shdrs and return that instead.306/// TODO actually create fake input shdrs and return that instead.
285pub fn inputShdr(self: ZigObject, atom_index: Atom.Index, elf_file: *Elf) Object.ElfShdr {307pub fn inputShdr(self: ZigObject, atom_index: Atom.Index, elf_file: *Elf) Object.ElfShdr {
286 _ = self;308 _ = self;
...@@ -334,7 +356,7 @@ pub fn resolveSymbols(self: *ZigObject, elf_file: *Elf) void {...@@ -334,7 +356,7 @@ pub fn resolveSymbols(self: *ZigObject, elf_file: *Elf) void {
334 }356 }
335}357}
336358
337pub fn claimUnresolved(self: *ZigObject, elf_file: *Elf) void {359pub fn claimUnresolved(self: ZigObject, elf_file: *Elf) void {
338 for (self.globals(), 0..) |index, i| {360 for (self.globals(), 0..) |index, i| {
339 const esym_index = @as(Symbol.Index, @intCast(i)) | global_symbol_bit;361 const esym_index = @as(Symbol.Index, @intCast(i)) | global_symbol_bit;
340 const esym = self.global_esyms.items(.elf_sym)[i];362 const esym = self.global_esyms.items(.elf_sym)[i];
...@@ -362,6 +384,26 @@ pub fn claimUnresolved(self: *ZigObject, elf_file: *Elf) void {...@@ -362,6 +384,26 @@ pub fn claimUnresolved(self: *ZigObject, elf_file: *Elf) void {
362 }384 }
363}385}
364386
387pub fn claimUnresolvedObject(self: ZigObject, elf_file: *Elf) void {
388 for (self.globals(), 0..) |index, i| {
389 const esym_index = @as(Symbol.Index, @intCast(i)) | global_symbol_bit;
390 const esym = self.global_esyms.items(.elf_sym)[i];
391
392 if (esym.st_shndx != elf.SHN_UNDEF) continue;
393
394 const global = elf_file.symbol(index);
395 if (global.file(elf_file)) |file| {
396 if (global.elfSym(elf_file).st_shndx != elf.SHN_UNDEF or
397 file.index() <= self.index) continue;
398 }
399
400 global.value = 0;
401 global.atom_index = 0;
402 global.esym_index = esym_index;
403 global.file_index = self.index;
404 }
405}
406
365pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void {407pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void {
366 for (self.atoms.items) |atom_index| {408 for (self.atoms.items) |atom_index| {
367 const atom = elf_file.atom(atom_index) orelse continue;409 const atom = elf_file.atom(atom_index) orelse continue;
...@@ -379,15 +421,6 @@ pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void {...@@ -379,15 +421,6 @@ pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void {
379 }421 }
380}422}
381423
382pub fn resetGlobals(self: *ZigObject, elf_file: *Elf) void {
383 for (self.globals()) |index| {
384 const global = elf_file.symbol(index);
385 const off = global.name_offset;
386 global.* = .{};
387 global.name_offset = off;
388 }
389}
390
391pub fn markLive(self: *ZigObject, elf_file: *Elf) void {424pub fn markLive(self: *ZigObject, elf_file: *Elf) void {
392 for (self.globals(), 0..) |index, i| {425 for (self.globals(), 0..) |index, i| {
393 const esym = self.global_esyms.items(.elf_sym)[i];426 const esym = self.global_esyms.items(.elf_sym)[i];
...@@ -404,79 +437,241 @@ pub fn markLive(self: *ZigObject, elf_file: *Elf) void {...@@ -404,79 +437,241 @@ pub fn markLive(self: *ZigObject, elf_file: *Elf) void {
404 }437 }
405}438}
406439
407pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) void {440fn sortSymbols(self: *ZigObject, elf_file: *Elf) error{OutOfMemory}!void {
408 for (self.locals()) |local_index| {441 _ = self;
409 const local = elf_file.symbol(local_index);442 _ = elf_file;
410 const esym = local.elfSym(elf_file);443 // const Entry = struct {
411 switch (esym.st_type()) {444 // index: Symbol.Index,
412 elf.STT_SECTION, elf.STT_NOTYPE => {445
413 local.flags.output_symtab = false;446 // const Ctx = struct {
414 continue;447 // zobj: ZigObject,
415 },448 // efile: *Elf,
416 else => {},449 // };
417 }450
418 local.flags.output_symtab = true;451 // pub fn lessThan(ctx: Ctx, lhs: @This(), rhs: @This()) bool {
419 self.output_symtab_size.nlocals += 1;452 // const lhs_sym = ctx.efile.symbol(zobj.symbol(lhs.index));
420 }453 // const rhs_sym = ctx.efile.symbol(zobj.symbol(rhs.index));
454 // if (lhs_sym.outputShndx() != null and rhs_sym.outputShndx() != null) {
455 // if (lhs_sym.output_section_index == rhs_sym.output_section_index) {
456 // if (lhs_sym.value == rhs_sym.value) {
457 // return lhs_sym.name_offset < rhs_sym.name_offset;
458 // }
459 // return lhs_sym.value < rhs_sym.value;
460 // }
461 // return lhs_sym.output_section_index < rhs_sym.output_section_index;
462 // }
463 // if (lhs_sym.outputShndx() != null) {
464 // if (rhs_sym.isAbs(ctx.efile)) return false;
465 // return true;
466 // }
467 // return false;
468 // }
469 // };
470
471 // const gpa = elf_file.base.allocator;
472
473 // {
474 // const sorted = try gpa.alloc(Entry, self.local_symbols.items.len);
475 // defer gpa.free(sorted);
476 // for (0..self.local_symbols.items.len) |index| {
477 // sorted[i] = .{ .index = @as(Symbol.Index, @intCast(index)) };
478 // }
479 // mem.sort(Entry, sorted, .{ .zobj = self, .efile = elf_file }, Entry.lessThan);
480
481 // const backlinks = try gpa.alloc(Symbol.Index, sorted.len);
482 // defer gpa.free(backlinks);
483 // for (sorted, 0..) |entry, i| {
484 // backlinks[entry.index] = @as(Symbol.Index, @intCast(i));
485 // }
486
487 // const local_symbols = try self.local_symbols.toOwnedSlice(gpa);
488 // defer gpa.free(local_symbols);
489
490 // try self.local_symbols.ensureTotalCapacityPrecise(gpa, local_symbols.len);
491 // for (sorted) |entry| {
492 // self.local_symbols.appendAssumeCapacity(local_symbols[entry.index]);
493 // }
494
495 // for (self.)
496 // }
497
498 // const sorted_globals = try gpa.alloc(Entry, self.global_symbols.items.len);
499 // defer gpa.free(sorted_globals);
500 // for (self.global_symbols.items, 0..) |index, i| {
501 // sorted_globals[i] = .{ .index = index };
502 // }
503 // mem.sort(Entry, sorted_globals, elf_file, Entry.lessThan);
504}
505
506pub fn updateArSymtab(self: ZigObject, ar_symtab: *Archive.ArSymtab, elf_file: *Elf) error{OutOfMemory}!void {
507 const gpa = elf_file.base.allocator;
508
509 try ar_symtab.symtab.ensureUnusedCapacity(gpa, self.globals().len);
421510
422 for (self.globals()) |global_index| {511 for (self.globals()) |global_index| {
423 const global = elf_file.symbol(global_index);512 const global = elf_file.symbol(global_index);
424 if (global.file(elf_file)) |file| if (file.index() != self.index) {513 const file_ptr = global.file(elf_file).?;
425 global.flags.output_symtab = false;514 assert(file_ptr.index() == self.index);
426 continue;515 if (global.type(elf_file) == elf.SHN_UNDEF) continue;
427 };516
428 global.flags.output_symtab = true;517 const off = try ar_symtab.strtab.insert(gpa, global.name(elf_file));
429 if (global.isLocal()) {518 ar_symtab.symtab.appendAssumeCapacity(.{ .off = off, .file_index = self.index });
430 self.output_symtab_size.nlocals += 1;
431 } else {
432 self.output_symtab_size.nglobals += 1;
433 }
434 }519 }
435}520}
436521
437pub fn writeSymtab(self: *ZigObject, elf_file: *Elf, ctx: anytype) void {522pub fn updateArStrtab(
438 var ilocal = ctx.ilocal;523 self: *ZigObject,
439 for (self.locals()) |local_index| {524 allocator: Allocator,
440 const local = elf_file.symbol(local_index);525 ar_strtab: *Archive.ArStrtab,
441 if (!local.flags.output_symtab) continue;526) error{OutOfMemory}!void {
442 local.setOutputSym(elf_file, &ctx.symtab[ilocal]);527 const name = try std.fmt.allocPrint(allocator, "{s}.o", .{std.fs.path.stem(self.path)});
443 ilocal += 1;528 defer allocator.free(name);
529 if (name.len <= 15) return;
530 const name_off = try ar_strtab.insert(allocator, name);
531 self.output_ar_state.name_off = name_off;
532}
533
534pub fn updateArSize(self: *ZigObject, elf_file: *Elf) void {
535 var end_pos: u64 = elf_file.shdr_table_offset.?;
536 for (elf_file.shdrs.items) |shdr| {
537 end_pos = @max(end_pos, shdr.sh_offset + shdr.sh_size);
444 }538 }
539 self.output_ar_state.size = end_pos;
540}
445541
446 var iglobal = ctx.iglobal;542pub fn writeAr(self: ZigObject, elf_file: *Elf, writer: anytype) !void {
447 for (self.globals()) |global_index| {543 const gpa = elf_file.base.allocator;
448 const global = elf_file.symbol(global_index);544
449 if (global.file(elf_file)) |file| if (file.index() != self.index) continue;545 const size = std.math.cast(usize, self.output_ar_state.size) orelse return error.Overflow;
450 if (!global.flags.output_symtab) continue;546 const contents = try gpa.alloc(u8, size);
451 if (global.isLocal()) {547 defer gpa.free(contents);
452 global.setOutputSym(elf_file, &ctx.symtab[ilocal]);548
453 ilocal += 1;549 const amt = try elf_file.base.file.?.preadAll(contents, 0);
454 } else {550 if (amt != self.output_ar_state.size) return error.InputOutput;
455 global.setOutputSym(elf_file, &ctx.symtab[iglobal]);551
456 iglobal += 1;552 const name = try std.fmt.allocPrint(gpa, "{s}.o", .{std.fs.path.stem(self.path)});
553 defer gpa.free(name);
554
555 const hdr = Archive.setArHdr(.{
556 .name = if (name.len <= 15) .{ .name = name } else .{ .name_off = self.output_ar_state.name_off },
557 .size = @intCast(size),
558 });
559 try writer.writeAll(mem.asBytes(&hdr));
560 try writer.writeAll(contents);
561}
562
563pub fn updateRelaSectionSizes(self: ZigObject, elf_file: *Elf) void {
564 _ = self;
565
566 for (&[_]?u16{
567 elf_file.zig_text_rela_section_index,
568 elf_file.zig_data_rel_ro_rela_section_index,
569 elf_file.zig_data_rela_section_index,
570 }) |maybe_index| {
571 const index = maybe_index orelse continue;
572 const shdr = &elf_file.shdrs.items[index];
573 const meta = elf_file.last_atom_and_free_list_table.get(@intCast(shdr.sh_info)).?;
574 const last_atom_index = meta.last_atom_index;
575
576 var atom = elf_file.atom(last_atom_index) orelse continue;
577 while (true) {
578 const relocs = atom.relocs(elf_file);
579 shdr.sh_size += relocs.len * shdr.sh_entsize;
580 if (elf_file.atom(atom.prev_index)) |prev| {
581 atom = prev;
582 } else break;
583 }
584 }
585
586 for (&[_]?u16{
587 elf_file.zig_text_rela_section_index,
588 elf_file.zig_data_rel_ro_rela_section_index,
589 elf_file.zig_data_rela_section_index,
590 }) |maybe_index| {
591 const index = maybe_index orelse continue;
592 const shdr = &elf_file.shdrs.items[index];
593 if (shdr.sh_size == 0) shdr.sh_offset = 0;
594 }
595}
596
597pub fn writeRelaSections(self: ZigObject, elf_file: *Elf) !void {
598 const gpa = elf_file.base.allocator;
599
600 for (&[_]?u16{
601 elf_file.zig_text_rela_section_index,
602 elf_file.zig_data_rel_ro_rela_section_index,
603 elf_file.zig_data_rela_section_index,
604 }) |maybe_index| {
605 const index = maybe_index orelse continue;
606 const shdr = elf_file.shdrs.items[index];
607 const meta = elf_file.last_atom_and_free_list_table.get(@intCast(shdr.sh_info)).?;
608 const last_atom_index = meta.last_atom_index;
609
610 var atom = elf_file.atom(last_atom_index) orelse continue;
611
612 var relocs = std.ArrayList(elf.Elf64_Rela).init(gpa);
613 defer relocs.deinit();
614 try relocs.ensureTotalCapacityPrecise(@intCast(@divExact(shdr.sh_size, shdr.sh_entsize)));
615
616 while (true) {
617 for (atom.relocs(elf_file)) |rel| {
618 const target = elf_file.symbol(self.symbol(rel.r_sym()));
619 const r_offset = atom.value + rel.r_offset;
620 const r_sym: u32 = if (target.flags.global)
621 (target.esym_index & symbol_mask) + @as(u32, @intCast(self.local_esyms.slice().len))
622 else
623 target.esym_index;
624 const r_type = switch (rel.r_type()) {
625 Elf.R_X86_64_ZIG_GOT32,
626 Elf.R_X86_64_ZIG_GOTPCREL,
627 => unreachable, // Sanity check if we accidentally emitted those.
628 else => |r_type| r_type,
629 };
630 relocs.appendAssumeCapacity(.{
631 .r_offset = r_offset,
632 .r_addend = rel.r_addend,
633 .r_info = (@as(u64, @intCast(r_sym + 1)) << 32) | r_type,
634 });
635 }
636 if (elf_file.atom(atom.prev_index)) |prev| {
637 atom = prev;
638 } else break;
457 }639 }
640
641 const SortRelocs = struct {
642 pub fn lessThan(ctx: void, lhs: elf.Elf64_Rela, rhs: elf.Elf64_Rela) bool {
643 _ = ctx;
644 return lhs.r_offset < rhs.r_offset;
645 }
646 };
647
648 mem.sort(elf.Elf64_Rela, relocs.items, {}, SortRelocs.lessThan);
649
650 try elf_file.base.file.?.pwriteAll(mem.sliceAsBytes(relocs.items), shdr.sh_offset);
458 }651 }
459}652}
460653
461pub fn symbol(self: *ZigObject, index: Symbol.Index) Symbol.Index {654inline fn isGlobal(index: Symbol.Index) bool {
462 const is_global = index & global_symbol_bit != 0;655 return index & global_symbol_bit != 0;
656}
657
658pub fn symbol(self: ZigObject, index: Symbol.Index) Symbol.Index {
463 const actual_index = index & symbol_mask;659 const actual_index = index & symbol_mask;
464 if (is_global) return self.global_symbols.items[actual_index];660 if (isGlobal(index)) return self.global_symbols.items[actual_index];
465 return self.local_symbols.items[actual_index];661 return self.local_symbols.items[actual_index];
466}662}
467663
468pub fn elfSym(self: *ZigObject, index: Symbol.Index) *elf.Elf64_Sym {664pub fn elfSym(self: *ZigObject, index: Symbol.Index) *elf.Elf64_Sym {
469 const is_global = index & global_symbol_bit != 0;
470 const actual_index = index & symbol_mask;665 const actual_index = index & symbol_mask;
471 if (is_global) return &self.global_esyms.items(.elf_sym)[actual_index];666 if (isGlobal(index)) return &self.global_esyms.items(.elf_sym)[actual_index];
472 return &self.local_esyms.items(.elf_sym)[actual_index];667 return &self.local_esyms.items(.elf_sym)[actual_index];
473}668}
474669
475pub fn locals(self: *ZigObject) []const Symbol.Index {670pub fn locals(self: ZigObject) []const Symbol.Index {
476 return self.local_symbols.items;671 return self.local_symbols.items;
477}672}
478673
479pub fn globals(self: *ZigObject) []const Symbol.Index {674pub fn globals(self: ZigObject) []const Symbol.Index {
480 return self.global_symbols.items;675 return self.global_symbols.items;
481}676}
482677
...@@ -570,7 +765,7 @@ pub fn lowerAnonDecl(...@@ -570,7 +765,7 @@ pub fn lowerAnonDecl(
570 name,765 name,
571 tv,766 tv,
572 decl_alignment,767 decl_alignment,
573 elf_file.zig_rodata_section_index.?,768 elf_file.zig_data_rel_ro_section_index.?,
574 src_loc,769 src_loc,
575 ) catch |err| switch (err) {770 ) catch |err| switch (err) {
576 error.OutOfMemory => return error.OutOfMemory,771 error.OutOfMemory => return error.OutOfMemory,
...@@ -682,7 +877,7 @@ fn getDeclShdrIndex(self: *ZigObject, elf_file: *Elf, decl_index: Module.Decl.In...@@ -682,7 +877,7 @@ fn getDeclShdrIndex(self: *ZigObject, elf_file: *Elf, decl_index: Module.Decl.In
682 .Fn => elf_file.zig_text_section_index.?,877 .Fn => elf_file.zig_text_section_index.?,
683 else => blk: {878 else => blk: {
684 if (decl.getOwnedVariable(mod)) |variable| {879 if (decl.getOwnedVariable(mod)) |variable| {
685 if (variable.is_const) break :blk elf_file.zig_rodata_section_index.?;880 if (variable.is_const) break :blk elf_file.zig_data_rel_ro_section_index.?;
686 if (variable.init.toValue().isUndefDeep(mod)) {881 if (variable.init.toValue().isUndefDeep(mod)) {
687 const mode = elf_file.base.options.optimize_mode;882 const mode = elf_file.base.options.optimize_mode;
688 if (mode == .Debug or mode == .ReleaseSafe) break :blk elf_file.zig_data_section_index.?;883 if (mode == .Debug or mode == .ReleaseSafe) break :blk elf_file.zig_data_section_index.?;
...@@ -696,7 +891,7 @@ fn getDeclShdrIndex(self: *ZigObject, elf_file: *Elf, decl_index: Module.Decl.In...@@ -696,7 +891,7 @@ fn getDeclShdrIndex(self: *ZigObject, elf_file: *Elf, decl_index: Module.Decl.In
696 if (is_all_zeroes) break :blk elf_file.zig_bss_section_index.?;891 if (is_all_zeroes) break :blk elf_file.zig_bss_section_index.?;
697 break :blk elf_file.zig_data_section_index.?;892 break :blk elf_file.zig_data_section_index.?;
698 }893 }
699 break :blk elf_file.zig_rodata_section_index.?;894 break :blk elf_file.zig_data_rel_ro_section_index.?;
700 },895 },
701 };896 };
702 return shdr_index;897 return shdr_index;
...@@ -727,7 +922,7 @@ fn updateDeclCode(...@@ -727,7 +922,7 @@ fn updateDeclCode(
727 sym.output_section_index = shdr_index;922 sym.output_section_index = shdr_index;
728 atom_ptr.output_section_index = shdr_index;923 atom_ptr.output_section_index = shdr_index;
729924
730 sym.name_offset = try elf_file.strtab.insert(gpa, decl_name);925 sym.name_offset = try self.strtab.insert(gpa, decl_name);
731 atom_ptr.flags.alive = true;926 atom_ptr.flags.alive = true;
732 atom_ptr.name_offset = sym.name_offset;927 atom_ptr.name_offset = sym.name_offset;
733 esym.st_name = sym.name_offset;928 esym.st_name = sym.name_offset;
...@@ -749,10 +944,12 @@ fn updateDeclCode(...@@ -749,10 +944,12 @@ fn updateDeclCode(
749 sym.value = atom_ptr.value;944 sym.value = atom_ptr.value;
750 esym.st_value = atom_ptr.value;945 esym.st_value = atom_ptr.value;
751946
752 log.debug(" (writing new offset table entry)", .{});947 if (!elf_file.isRelocatable()) {
753 assert(sym.flags.has_zig_got);948 log.debug(" (writing new offset table entry)", .{});
754 const extra = sym.extra(elf_file).?;949 assert(sym.flags.has_zig_got);
755 try elf_file.zig_got.writeOne(elf_file, extra.zig_got);950 const extra = sym.extra(elf_file).?;
951 try elf_file.zig_got.writeOne(elf_file, extra.zig_got);
952 }
756 }953 }
757 } else if (code.len < old_size) {954 } else if (code.len < old_size) {
758 atom_ptr.shrink(elf_file);955 atom_ptr.shrink(elf_file);
...@@ -762,10 +959,13 @@ fn updateDeclCode(...@@ -762,10 +959,13 @@ fn updateDeclCode(
762 errdefer self.freeDeclMetadata(elf_file, sym_index);959 errdefer self.freeDeclMetadata(elf_file, sym_index);
763960
764 sym.value = atom_ptr.value;961 sym.value = atom_ptr.value;
962 sym.flags.needs_zig_got = true;
765 esym.st_value = atom_ptr.value;963 esym.st_value = atom_ptr.value;
766964
767 const gop = try sym.getOrCreateZigGotEntry(sym_index, elf_file);965 if (!elf_file.isRelocatable()) {
768 try elf_file.zig_got.writeOne(elf_file, gop.index);966 const gop = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
967 try elf_file.zig_got.writeOne(elf_file, gop.index);
968 }
769 }969 }
770970
771 if (elf_file.base.child_pid) |pid| {971 if (elf_file.base.child_pid) |pid| {
...@@ -791,9 +991,7 @@ fn updateDeclCode(...@@ -791,9 +991,7 @@ fn updateDeclCode(
791991
792 const shdr = elf_file.shdrs.items[shdr_index];992 const shdr = elf_file.shdrs.items[shdr_index];
793 if (shdr.sh_type != elf.SHT_NOBITS) {993 if (shdr.sh_type != elf.SHT_NOBITS) {
794 const phdr_index = elf_file.phdr_to_shdr_table.get(shdr_index).?;994 const file_offset = shdr.sh_offset + sym.value - shdr.sh_addr;
795 const section_offset = sym.value - elf_file.phdrs.items[phdr_index].p_vaddr;
796 const file_offset = shdr.sh_offset + section_offset;
797 try elf_file.base.file.?.pwriteAll(code, file_offset);995 try elf_file.base.file.?.pwriteAll(code, file_offset);
798 }996 }
799}997}
...@@ -967,7 +1165,7 @@ fn updateLazySymbol(...@@ -967,7 +1165,7 @@ fn updateLazySymbol(
967 sym.ty.fmt(mod),1165 sym.ty.fmt(mod),
968 });1166 });
969 defer gpa.free(name);1167 defer gpa.free(name);
970 break :blk try elf_file.strtab.insert(gpa, name);1168 break :blk try self.strtab.insert(gpa, name);
971 };1169 };
9721170
973 const src = if (sym.ty.getOwnerDeclOrNull(mod)) |owner_decl|1171 const src = if (sym.ty.getOwnerDeclOrNull(mod)) |owner_decl|
...@@ -997,10 +1195,9 @@ fn updateLazySymbol(...@@ -997,10 +1195,9 @@ fn updateLazySymbol(
9971195
998 const output_section_index = switch (sym.kind) {1196 const output_section_index = switch (sym.kind) {
999 .code => elf_file.zig_text_section_index.?,1197 .code => elf_file.zig_text_section_index.?,
1000 .const_data => elf_file.zig_rodata_section_index.?,1198 .const_data => elf_file.zig_data_rel_ro_section_index.?,
1001 };1199 };
1002 const local_sym = elf_file.symbol(symbol_index);1200 const local_sym = elf_file.symbol(symbol_index);
1003 const phdr_index = elf_file.phdr_to_shdr_table.get(output_section_index).?;
1004 local_sym.name_offset = name_str_index;1201 local_sym.name_offset = name_str_index;
1005 local_sym.output_section_index = output_section_index;1202 local_sym.output_section_index = output_section_index;
1006 const local_esym = &self.local_esyms.items(.elf_sym)[local_sym.esym_index];1203 const local_esym = &self.local_esyms.items(.elf_sym)[local_sym.esym_index];
...@@ -1018,13 +1215,16 @@ fn updateLazySymbol(...@@ -1018,13 +1215,16 @@ fn updateLazySymbol(
1018 errdefer self.freeDeclMetadata(elf_file, symbol_index);1215 errdefer self.freeDeclMetadata(elf_file, symbol_index);
10191216
1020 local_sym.value = atom_ptr.value;1217 local_sym.value = atom_ptr.value;
1218 local_sym.flags.needs_zig_got = true;
1021 local_esym.st_value = atom_ptr.value;1219 local_esym.st_value = atom_ptr.value;
10221220
1023 const gop = try local_sym.getOrCreateZigGotEntry(symbol_index, elf_file);1221 if (!elf_file.isRelocatable()) {
1024 try elf_file.zig_got.writeOne(elf_file, gop.index);1222 const gop = try local_sym.getOrCreateZigGotEntry(symbol_index, elf_file);
1223 try elf_file.zig_got.writeOne(elf_file, gop.index);
1224 }
10251225
1026 const section_offset = atom_ptr.value - elf_file.phdrs.items[phdr_index].p_vaddr;1226 const shdr = elf_file.shdrs.items[output_section_index];
1027 const file_offset = elf_file.shdrs.items[output_section_index].sh_offset + section_offset;1227 const file_offset = shdr.sh_offset + atom_ptr.value - shdr.sh_addr;
1028 try elf_file.base.file.?.pwriteAll(code, file_offset);1228 try elf_file.base.file.?.pwriteAll(code, file_offset);
1029}1229}
10301230
...@@ -1051,7 +1251,7 @@ pub fn lowerUnnamedConst(...@@ -1051,7 +1251,7 @@ pub fn lowerUnnamedConst(
1051 name,1251 name,
1052 typed_value,1252 typed_value,
1053 typed_value.ty.abiAlignment(mod),1253 typed_value.ty.abiAlignment(mod),
1054 elf_file.zig_rodata_section_index.?,1254 elf_file.zig_data_rel_ro_section_index.?,
1055 decl.srcLoc(mod),1255 decl.srcLoc(mod),
1056 )) {1256 )) {
1057 .ok => |sym_index| sym_index,1257 .ok => |sym_index| sym_index,
...@@ -1098,9 +1298,8 @@ fn lowerConst(...@@ -1098,9 +1298,8 @@ fn lowerConst(
1098 .fail => |em| return .{ .fail = em },1298 .fail => |em| return .{ .fail = em },
1099 };1299 };
11001300
1101 const phdr_index = elf_file.phdr_to_shdr_table.get(output_section_index).?;
1102 const local_sym = elf_file.symbol(sym_index);1301 const local_sym = elf_file.symbol(sym_index);
1103 const name_str_index = try elf_file.strtab.insert(gpa, name);1302 const name_str_index = try self.strtab.insert(gpa, name);
1104 local_sym.name_offset = name_str_index;1303 local_sym.name_offset = name_str_index;
1105 local_sym.output_section_index = output_section_index;1304 local_sym.output_section_index = output_section_index;
1106 const local_esym = &self.local_esyms.items(.elf_sym)[local_sym.esym_index];1305 const local_esym = &self.local_esyms.items(.elf_sym)[local_sym.esym_index];
...@@ -1121,8 +1320,8 @@ fn lowerConst(...@@ -1121,8 +1320,8 @@ fn lowerConst(
1121 local_sym.value = atom_ptr.value;1320 local_sym.value = atom_ptr.value;
1122 local_esym.st_value = atom_ptr.value;1321 local_esym.st_value = atom_ptr.value;
11231322
1124 const section_offset = atom_ptr.value - elf_file.phdrs.items[phdr_index].p_vaddr;1323 const shdr = elf_file.shdrs.items[output_section_index];
1125 const file_offset = elf_file.shdrs.items[output_section_index].sh_offset + section_offset;1324 const file_offset = shdr.sh_offset + atom_ptr.value - shdr.sh_addr;
1126 try elf_file.base.file.?.pwriteAll(code, file_offset);1325 try elf_file.base.file.?.pwriteAll(code, file_offset);
11271326
1128 return .{ .ok = sym_index };1327 return .{ .ok = sym_index };
...@@ -1195,18 +1394,12 @@ pub fn updateExports(...@@ -1195,18 +1394,12 @@ pub fn updateExports(
1195 };1394 };
1196 const stt_bits: u8 = @as(u4, @truncate(esym.st_info));1395 const stt_bits: u8 = @as(u4, @truncate(esym.st_info));
1197 const exp_name = mod.intern_pool.stringToSlice(exp.opts.name);1396 const exp_name = mod.intern_pool.stringToSlice(exp.opts.name);
1198 const name_off = try elf_file.strtab.insert(gpa, exp_name);1397 const name_off = try self.strtab.insert(gpa, exp_name);
1199 const global_esym_index = if (metadata.@"export"(self, elf_file, exp_name)) |exp_index|1398 const global_esym_index = if (metadata.@"export"(self, exp_name)) |exp_index|
1200 exp_index.*1399 exp_index.*
1201 else blk: {1400 else blk: {
1202 const global_esym_index = try self.addGlobalEsym(gpa);1401 const global_esym_index = try self.getGlobalSymbol(elf_file, exp_name, null);
1203 const lookup_gop = try self.globals_lookup.getOrPut(gpa, name_off);
1204 const global_esym = self.elfSym(global_esym_index);
1205 global_esym.st_name = name_off;
1206 lookup_gop.value_ptr.* = global_esym_index;
1207 try metadata.exports.append(gpa, global_esym_index);1402 try metadata.exports.append(gpa, global_esym_index);
1208 const gop = try elf_file.getOrPutGlobal(name_off);
1209 try self.global_symbols.append(gpa, gop.index);
1210 break :blk global_esym_index;1403 break :blk global_esym_index;
1211 };1404 };
12121405
...@@ -1216,6 +1409,7 @@ pub fn updateExports(...@@ -1216,6 +1409,7 @@ pub fn updateExports(
1216 global_esym.st_shndx = esym.st_shndx;1409 global_esym.st_shndx = esym.st_shndx;
1217 global_esym.st_info = (stb_bits << 4) | stt_bits;1410 global_esym.st_info = (stb_bits << 4) | stt_bits;
1218 global_esym.st_name = name_off;1411 global_esym.st_name = name_off;
1412 global_esym.st_size = esym.st_size;
1219 self.global_esyms.items(.shndx)[actual_esym_index] = esym_shndx;1413 self.global_esyms.items(.shndx)[actual_esym_index] = esym_shndx;
1220 }1414 }
1221}1415}
...@@ -1248,7 +1442,7 @@ pub fn deleteDeclExport(...@@ -1248,7 +1442,7 @@ pub fn deleteDeclExport(
1248 const metadata = self.decls.getPtr(decl_index) orelse return;1442 const metadata = self.decls.getPtr(decl_index) orelse return;
1249 const mod = elf_file.base.options.module.?;1443 const mod = elf_file.base.options.module.?;
1250 const exp_name = mod.intern_pool.stringToSlice(name);1444 const exp_name = mod.intern_pool.stringToSlice(name);
1251 const esym_index = metadata.@"export"(self, elf_file, exp_name) orelse return;1445 const esym_index = metadata.@"export"(self, exp_name) orelse return;
1252 log.debug("deleting export '{s}'", .{exp_name});1446 log.debug("deleting export '{s}'", .{exp_name});
1253 const esym = &self.global_esyms.items(.elf_sym)[esym_index.*];1447 const esym = &self.global_esyms.items(.elf_sym)[esym_index.*];
1254 _ = self.globals_lookup.remove(esym.st_name);1448 _ = self.globals_lookup.remove(esym.st_name);
...@@ -1265,19 +1459,23 @@ pub fn deleteDeclExport(...@@ -1265,19 +1459,23 @@ pub fn deleteDeclExport(
1265pub fn getGlobalSymbol(self: *ZigObject, elf_file: *Elf, name: []const u8, lib_name: ?[]const u8) !u32 {1459pub fn getGlobalSymbol(self: *ZigObject, elf_file: *Elf, name: []const u8, lib_name: ?[]const u8) !u32 {
1266 _ = lib_name;1460 _ = lib_name;
1267 const gpa = elf_file.base.allocator;1461 const gpa = elf_file.base.allocator;
1268 const off = try elf_file.strtab.insert(gpa, name);1462 const off = try self.strtab.insert(gpa, name);
1269 const lookup_gop = try self.globals_lookup.getOrPut(gpa, off);1463 const lookup_gop = try self.globals_lookup.getOrPut(gpa, off);
1270 if (!lookup_gop.found_existing) {1464 if (!lookup_gop.found_existing) {
1271 const esym_index = try self.addGlobalEsym(gpa);1465 const esym_index = try self.addGlobalEsym(gpa);
1272 const esym = self.elfSym(esym_index);1466 const esym = self.elfSym(esym_index);
1273 esym.st_name = off;1467 esym.st_name = off;
1274 lookup_gop.value_ptr.* = esym_index;1468 lookup_gop.value_ptr.* = esym_index;
1275 const gop = try elf_file.getOrPutGlobal(off);1469 const gop = try elf_file.getOrPutGlobal(name);
1276 try self.global_symbols.append(gpa, gop.index);1470 try self.global_symbols.append(gpa, gop.index);
1277 }1471 }
1278 return lookup_gop.value_ptr.*;1472 return lookup_gop.value_ptr.*;
1279}1473}
12801474
1475pub fn getString(self: ZigObject, off: u32) [:0]const u8 {
1476 return self.strtab.getAssumeExists(off);
1477}
1478
1281pub fn fmtSymtab(self: *ZigObject, elf_file: *Elf) std.fmt.Formatter(formatSymtab) {1479pub fn fmtSymtab(self: *ZigObject, elf_file: *Elf) std.fmt.Formatter(formatSymtab) {
1282 return .{ .data = .{1480 return .{ .data = .{
1283 .self = self,1481 .self = self,
...@@ -1350,9 +1548,9 @@ const DeclMetadata = struct {...@@ -1350,9 +1548,9 @@ const DeclMetadata = struct {
1350 /// A list of all exports aliases of this Decl.1548 /// A list of all exports aliases of this Decl.
1351 exports: std.ArrayListUnmanaged(Symbol.Index) = .{},1549 exports: std.ArrayListUnmanaged(Symbol.Index) = .{},
13521550
1353 fn @"export"(m: DeclMetadata, zig_object: *ZigObject, elf_file: *Elf, name: []const u8) ?*u32 {1551 fn @"export"(m: DeclMetadata, zig_object: *ZigObject, name: []const u8) ?*u32 {
1354 for (m.exports.items) |*exp| {1552 for (m.exports.items) |*exp| {
1355 const exp_name = elf_file.strtab.getAssumeExists(zig_object.elfSym(exp.*).st_name);1553 const exp_name = zig_object.getString(zig_object.elfSym(exp.*).st_name);
1356 if (mem.eql(u8, name, exp_name)) return exp;1554 if (mem.eql(u8, name, exp_name)) return exp;
1357 }1555 }
1358 return null;1556 return null;
...@@ -1377,6 +1575,7 @@ const std = @import("std");...@@ -1377,6 +1575,7 @@ const std = @import("std");
13771575
1378const Air = @import("../../Air.zig");1576const Air = @import("../../Air.zig");
1379const Allocator = std.mem.Allocator;1577const Allocator = std.mem.Allocator;
1578const Archive = @import("Archive.zig");
1380const Atom = @import("Atom.zig");1579const Atom = @import("Atom.zig");
1381const Dwarf = @import("../Dwarf.zig");1580const Dwarf = @import("../Dwarf.zig");
1382const Elf = @import("../Elf.zig");1581const Elf = @import("../Elf.zig");
...@@ -1386,5 +1585,6 @@ const Liveness = @import("../../Liveness.zig");...@@ -1386,5 +1585,6 @@ const Liveness = @import("../../Liveness.zig");
1386const Module = @import("../../Module.zig");1585const Module = @import("../../Module.zig");
1387const Object = @import("Object.zig");1586const Object = @import("Object.zig");
1388const Symbol = @import("Symbol.zig");1587const Symbol = @import("Symbol.zig");
1588const StringTable = @import("../StringTable.zig");
1389const TypedValue = @import("../../TypedValue.zig");1589const TypedValue = @import("../../TypedValue.zig");
1390const ZigObject = @This();1590const ZigObject = @This();
src/link/Elf/eh_frame.zig+1-1
...@@ -43,7 +43,7 @@ pub const Fde = struct {...@@ -43,7 +43,7 @@ pub const Fde = struct {
43 pub fn atom(fde: Fde, elf_file: *Elf) *Atom {43 pub fn atom(fde: Fde, elf_file: *Elf) *Atom {
44 const object = elf_file.file(fde.file_index).?.object;44 const object = elf_file.file(fde.file_index).?.object;
45 const rel = fde.relocs(elf_file)[0];45 const rel = fde.relocs(elf_file)[0];
46 const sym = object.symtab[rel.r_sym()];46 const sym = object.symtab.items[rel.r_sym()];
47 const atom_index = object.atoms.items[sym.st_shndx];47 const atom_index = object.atoms.items[sym.st_shndx];
48 return elf_file.atom(atom_index).?;48 return elf_file.atom(atom_index).?;
49 }49 }
src/link/Elf/file.zig+103-8
...@@ -68,9 +68,12 @@ pub const File = union(enum) {...@@ -68,9 +68,12 @@ pub const File = union(enum) {
68 }68 }
6969
70 pub fn resetGlobals(file: File, elf_file: *Elf) void {70 pub fn resetGlobals(file: File, elf_file: *Elf) void {
71 switch (file) {71 for (file.globals()) |global_index| {
72 .linker_defined => unreachable,72 const global = elf_file.symbol(global_index);
73 inline else => |x| x.resetGlobals(elf_file),73 const name_offset = global.name_offset;
74 global.* = .{};
75 global.name_offset = name_offset;
76 global.flags.global = true;
74 }77 }
75 }78 }
7679
...@@ -83,24 +86,37 @@ pub const File = union(enum) {...@@ -83,24 +86,37 @@ pub const File = union(enum) {
8386
84 pub fn markLive(file: File, elf_file: *Elf) void {87 pub fn markLive(file: File, elf_file: *Elf) void {
85 switch (file) {88 switch (file) {
86 .linker_defined => unreachable,89 .linker_defined => {},
87 inline else => |x| x.markLive(elf_file),90 inline else => |x| x.markLive(elf_file),
88 }91 }
89 }92 }
9093
91 pub fn atoms(file: File) []const Atom.Index {94 pub fn atoms(file: File) []const Atom.Index {
92 return switch (file) {95 return switch (file) {
93 .linker_defined => unreachable,96 .linker_defined, .shared_object => &[0]Atom.Index{},
94 .shared_object => unreachable,
95 .zig_object => |x| x.atoms.items,97 .zig_object => |x| x.atoms.items,
96 .object => |x| x.atoms.items,98 .object => |x| x.atoms.items,
97 };99 };
98 }100 }
99101
102 pub fn cies(file: File) []const Cie {
103 return switch (file) {
104 .zig_object => &[0]Cie{},
105 .object => |x| x.cies.items,
106 inline else => unreachable,
107 };
108 }
109
110 pub fn symbol(file: File, ind: Symbol.Index) Symbol.Index {
111 return switch (file) {
112 .zig_object => |x| x.symbol(ind),
113 inline else => |x| x.symbols.items[ind],
114 };
115 }
116
100 pub fn locals(file: File) []const Symbol.Index {117 pub fn locals(file: File) []const Symbol.Index {
101 return switch (file) {118 return switch (file) {
102 .linker_defined => unreachable,119 .linker_defined, .shared_object => &[0]Symbol.Index{},
103 .shared_object => unreachable,
104 inline else => |x| x.locals(),120 inline else => |x| x.locals(),
105 };121 };
106 }122 }
...@@ -111,6 +127,83 @@ pub const File = union(enum) {...@@ -111,6 +127,83 @@ pub const File = union(enum) {
111 };127 };
112 }128 }
113129
130 pub fn updateSymtabSize(file: File, elf_file: *Elf) void {
131 const output_symtab_size = switch (file) {
132 inline else => |x| &x.output_symtab_size,
133 };
134 for (file.locals()) |local_index| {
135 const local = elf_file.symbol(local_index);
136 if (local.atom(elf_file)) |atom| if (!atom.flags.alive) continue;
137 const esym = local.elfSym(elf_file);
138 switch (esym.st_type()) {
139 elf.STT_SECTION => if (!elf_file.isRelocatable()) continue,
140 elf.STT_NOTYPE => continue,
141 else => {},
142 }
143 local.flags.output_symtab = true;
144 output_symtab_size.nlocals += 1;
145 output_symtab_size.strsize += @as(u32, @intCast(local.name(elf_file).len)) + 1;
146 }
147
148 for (file.globals()) |global_index| {
149 const global = elf_file.symbol(global_index);
150 const file_ptr = global.file(elf_file) orelse continue;
151 if (file_ptr.index() != file.index()) continue;
152 if (global.atom(elf_file)) |atom| if (!atom.flags.alive) continue;
153 global.flags.output_symtab = true;
154 if (global.isLocal(elf_file)) {
155 output_symtab_size.nlocals += 1;
156 } else {
157 output_symtab_size.nglobals += 1;
158 }
159 output_symtab_size.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1;
160 }
161 }
162
163 pub fn writeSymtab(file: File, elf_file: *Elf, ctx: anytype) void {
164 var ilocal = ctx.ilocal;
165 for (file.locals()) |local_index| {
166 const local = elf_file.symbol(local_index);
167 if (!local.flags.output_symtab) continue;
168 const out_sym = &elf_file.symtab.items[ilocal];
169 out_sym.st_name = @intCast(elf_file.strtab.items.len);
170 elf_file.strtab.appendSliceAssumeCapacity(local.name(elf_file));
171 elf_file.strtab.appendAssumeCapacity(0);
172 local.setOutputSym(elf_file, out_sym);
173 ilocal += 1;
174 }
175
176 var iglobal = ctx.iglobal;
177 for (file.globals()) |global_index| {
178 const global = elf_file.symbol(global_index);
179 const file_ptr = global.file(elf_file) orelse continue;
180 if (file_ptr.index() != file.index()) continue;
181 if (!global.flags.output_symtab) continue;
182 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
183 elf_file.strtab.appendSliceAssumeCapacity(global.name(elf_file));
184 elf_file.strtab.appendAssumeCapacity(0);
185 if (global.isLocal(elf_file)) {
186 const out_sym = &elf_file.symtab.items[ilocal];
187 out_sym.st_name = st_name;
188 global.setOutputSym(elf_file, out_sym);
189 ilocal += 1;
190 } else {
191 const out_sym = &elf_file.symtab.items[iglobal];
192 out_sym.st_name = st_name;
193 global.setOutputSym(elf_file, out_sym);
194 iglobal += 1;
195 }
196 }
197 }
198
199 pub fn updateArSymtab(file: File, ar_symtab: *Archive.ArSymtab, elf_file: *Elf) !void {
200 return switch (file) {
201 .zig_object => |x| x.updateArSymtab(ar_symtab, elf_file),
202 .object => @panic("TODO"),
203 inline else => unreachable,
204 };
205 }
206
114 pub const Index = u32;207 pub const Index = u32;
115208
116 pub const Entry = union(enum) {209 pub const Entry = union(enum) {
...@@ -126,7 +219,9 @@ const std = @import("std");...@@ -126,7 +219,9 @@ const std = @import("std");
126const elf = std.elf;219const elf = std.elf;
127220
128const Allocator = std.mem.Allocator;221const Allocator = std.mem.Allocator;
222const Archive = @import("Archive.zig");
129const Atom = @import("Atom.zig");223const Atom = @import("Atom.zig");
224const Cie = @import("eh_frame.zig").Cie;
130const Elf = @import("../Elf.zig");225const Elf = @import("../Elf.zig");
131const LinkerDefined = @import("LinkerDefined.zig");226const LinkerDefined = @import("LinkerDefined.zig");
132const Object = @import("Object.zig");227const Object = @import("Object.zig");
src/link/Elf/gc.zig+26-17
...@@ -1,19 +1,27 @@...@@ -1,19 +1,27 @@
1pub fn gcAtoms(elf_file: *Elf) !void {1pub fn gcAtoms(elf_file: *Elf) !void {
2 var roots = std.ArrayList(*Atom).init(elf_file.base.allocator);2 const gpa = elf_file.base.allocator;
3 const num_files = elf_file.objects.items.len + @intFromBool(elf_file.zig_object_index != null);
4 var files = try std.ArrayList(File.Index).initCapacity(gpa, num_files);
5 defer files.deinit();
6 if (elf_file.zig_object_index) |index| files.appendAssumeCapacity(index);
7 for (elf_file.objects.items) |index| files.appendAssumeCapacity(index);
8
9 var roots = std.ArrayList(*Atom).init(gpa);
3 defer roots.deinit();10 defer roots.deinit();
4 try collectRoots(&roots, elf_file);11 try collectRoots(&roots, files.items, elf_file);
12
5 mark(roots, elf_file);13 mark(roots, elf_file);
6 prune(elf_file);14 prune(files.items, elf_file);
7}15}
816
9fn collectRoots(roots: *std.ArrayList(*Atom), elf_file: *Elf) !void {17fn collectRoots(roots: *std.ArrayList(*Atom), files: []const File.Index, elf_file: *Elf) !void {
10 if (elf_file.entry_index) |index| {18 if (elf_file.entry_index) |index| {
11 const global = elf_file.symbol(index);19 const global = elf_file.symbol(index);
12 try markSymbol(global, roots, elf_file);20 try markSymbol(global, roots, elf_file);
13 }21 }
1422
15 for (elf_file.objects.items) |index| {23 for (files) |index| {
16 for (elf_file.file(index).?.object.globals()) |global_index| {24 for (elf_file.file(index).?.globals()) |global_index| {
17 const global = elf_file.symbol(global_index);25 const global = elf_file.symbol(global_index);
18 if (global.file(elf_file)) |file| {26 if (global.file(elf_file)) |file| {
19 if (file.index() == index and global.flags.@"export")27 if (file.index() == index and global.flags.@"export")
...@@ -22,10 +30,10 @@ fn collectRoots(roots: *std.ArrayList(*Atom), elf_file: *Elf) !void {...@@ -22,10 +30,10 @@ fn collectRoots(roots: *std.ArrayList(*Atom), elf_file: *Elf) !void {
22 }30 }
23 }31 }
2432
25 for (elf_file.objects.items) |index| {33 for (files) |index| {
26 const object = elf_file.file(index).?.object;34 const file = elf_file.file(index).?;
2735
28 for (object.atoms.items) |atom_index| {36 for (file.atoms()) |atom_index| {
29 const atom = elf_file.atom(atom_index) orelse continue;37 const atom = elf_file.atom(atom_index) orelse continue;
30 if (!atom.flags.alive) continue;38 if (!atom.flags.alive) continue;
3139
...@@ -49,9 +57,9 @@ fn collectRoots(roots: *std.ArrayList(*Atom), elf_file: *Elf) !void {...@@ -49,9 +57,9 @@ fn collectRoots(roots: *std.ArrayList(*Atom), elf_file: *Elf) !void {
49 }57 }
5058
51 // Mark every atom referenced by CIE as alive.59 // Mark every atom referenced by CIE as alive.
52 for (object.cies.items) |cie| {60 for (file.cies()) |cie| {
53 for (cie.relocs(elf_file)) |rel| {61 for (cie.relocs(elf_file)) |rel| {
54 const sym = elf_file.symbol(object.symbols.items[rel.r_sym()]);62 const sym = elf_file.symbol(file.symbol(rel.r_sym()));
55 try markSymbol(sym, roots, elf_file);63 try markSymbol(sym, roots, elf_file);
56 }64 }
57 }65 }
...@@ -73,11 +81,11 @@ fn markLive(atom: *Atom, elf_file: *Elf) void {...@@ -73,11 +81,11 @@ fn markLive(atom: *Atom, elf_file: *Elf) void {
73 if (@import("build_options").enable_logging) track_live_level.incr();81 if (@import("build_options").enable_logging) track_live_level.incr();
7482
75 assert(atom.flags.visited);83 assert(atom.flags.visited);
76 const object = atom.file(elf_file).?.object;84 const file = atom.file(elf_file).?;
7785
78 for (atom.fdes(elf_file)) |fde| {86 for (atom.fdes(elf_file)) |fde| {
79 for (fde.relocs(elf_file)[1..]) |rel| {87 for (fde.relocs(elf_file)[1..]) |rel| {
80 const target_sym = elf_file.symbol(object.symbols.items[rel.r_sym()]);88 const target_sym = elf_file.symbol(file.symbol(rel.r_sym()));
81 const target_atom = target_sym.atom(elf_file) orelse continue;89 const target_atom = target_sym.atom(elf_file) orelse continue;
82 target_atom.flags.alive = true;90 target_atom.flags.alive = true;
83 gc_track_live_log.debug("{}marking live atom({d})", .{ track_live_level, target_atom.atom_index });91 gc_track_live_log.debug("{}marking live atom({d})", .{ track_live_level, target_atom.atom_index });
...@@ -86,7 +94,7 @@ fn markLive(atom: *Atom, elf_file: *Elf) void {...@@ -86,7 +94,7 @@ fn markLive(atom: *Atom, elf_file: *Elf) void {
86 }94 }
8795
88 for (atom.relocs(elf_file)) |rel| {96 for (atom.relocs(elf_file)) |rel| {
89 const target_sym = elf_file.symbol(object.symbols.items[rel.r_sym()]);97 const target_sym = elf_file.symbol(file.symbol(rel.r_sym()));
90 const target_atom = target_sym.atom(elf_file) orelse continue;98 const target_atom = target_sym.atom(elf_file) orelse continue;
91 target_atom.flags.alive = true;99 target_atom.flags.alive = true;
92 gc_track_live_log.debug("{}marking live atom({d})", .{ track_live_level, target_atom.atom_index });100 gc_track_live_log.debug("{}marking live atom({d})", .{ track_live_level, target_atom.atom_index });
...@@ -101,9 +109,9 @@ fn mark(roots: std.ArrayList(*Atom), elf_file: *Elf) void {...@@ -101,9 +109,9 @@ fn mark(roots: std.ArrayList(*Atom), elf_file: *Elf) void {
101 }109 }
102}110}
103111
104fn prune(elf_file: *Elf) void {112fn prune(files: []const File.Index, elf_file: *Elf) void {
105 for (elf_file.objects.items) |index| {113 for (files) |index| {
106 for (elf_file.file(index).?.object.atoms.items) |atom_index| {114 for (elf_file.file(index).?.atoms()) |atom_index| {
107 const atom = elf_file.atom(atom_index) orelse continue;115 const atom = elf_file.atom(atom_index) orelse continue;
108 if (atom.flags.alive and !atom.flags.visited) {116 if (atom.flags.alive and !atom.flags.visited) {
109 atom.flags.alive = false;117 atom.flags.alive = false;
...@@ -158,4 +166,5 @@ const mem = std.mem;...@@ -158,4 +166,5 @@ const mem = std.mem;
158const Allocator = mem.Allocator;166const Allocator = mem.Allocator;
159const Atom = @import("Atom.zig");167const Atom = @import("Atom.zig");
160const Elf = @import("../Elf.zig");168const Elf = @import("../Elf.zig");
169const File = @import("file.zig").File;
161const Symbol = @import("Symbol.zig");170const Symbol = @import("Symbol.zig");
src/link/Elf/synthetic_sections.zig+39-67
...@@ -9,7 +9,7 @@ pub const DynamicSection = struct {...@@ -9,7 +9,7 @@ pub const DynamicSection = struct {
99
10 pub fn addNeeded(dt: *DynamicSection, shared: *SharedObject, elf_file: *Elf) !void {10 pub fn addNeeded(dt: *DynamicSection, shared: *SharedObject, elf_file: *Elf) !void {
11 const gpa = elf_file.base.allocator;11 const gpa = elf_file.base.allocator;
12 const off = try elf_file.dynstrtab.insert(gpa, shared.soname());12 const off = try elf_file.insertDynString(shared.soname());
13 try dt.needed.append(gpa, off);13 try dt.needed.append(gpa, off);
14 }14 }
1515
...@@ -22,11 +22,11 @@ pub const DynamicSection = struct {...@@ -22,11 +22,11 @@ pub const DynamicSection = struct {
22 if (i > 0) try rpath.append(':');22 if (i > 0) try rpath.append(':');
23 try rpath.appendSlice(path);23 try rpath.appendSlice(path);
24 }24 }
25 dt.rpath = try elf_file.dynstrtab.insert(gpa, rpath.items);25 dt.rpath = try elf_file.insertDynString(rpath.items);
26 }26 }
2727
28 pub fn setSoname(dt: *DynamicSection, soname: []const u8, elf_file: *Elf) !void {28 pub fn setSoname(dt: *DynamicSection, soname: []const u8, elf_file: *Elf) !void {
29 dt.soname = try elf_file.dynstrtab.insert(elf_file.base.allocator, soname);29 dt.soname = try elf_file.insertDynString(soname);
30 }30 }
3131
32 fn getFlags(dt: DynamicSection, elf_file: *Elf) ?u64 {32 fn getFlags(dt: DynamicSection, elf_file: *Elf) ?u64 {
...@@ -359,31 +359,24 @@ pub const ZigGotSection = struct {...@@ -359,31 +359,24 @@ pub const ZigGotSection = struct {
359 }359 }
360360
361 pub fn updateSymtabSize(zig_got: *ZigGotSection, elf_file: *Elf) void {361 pub fn updateSymtabSize(zig_got: *ZigGotSection, elf_file: *Elf) void {
362 _ = elf_file;
363 zig_got.output_symtab_size.nlocals = @as(u32, @intCast(zig_got.entries.items.len));362 zig_got.output_symtab_size.nlocals = @as(u32, @intCast(zig_got.entries.items.len));
364 }
365
366 pub fn updateStrtab(zig_got: ZigGotSection, elf_file: *Elf) !void {
367 const gpa = elf_file.base.allocator;
368 for (zig_got.entries.items) |entry| {363 for (zig_got.entries.items) |entry| {
369 const symbol_name = elf_file.symbol(entry).name(elf_file);364 const name = elf_file.symbol(entry).name(elf_file);
370 const name = try std.fmt.allocPrint(gpa, "{s}$ziggot", .{symbol_name});365 zig_got.output_symtab_size.strsize += @as(u32, @intCast(name.len + "$ziggot".len)) + 1;
371 defer gpa.free(name);
372 _ = try elf_file.strtab.insert(gpa, name);
373 }366 }
374 }367 }
375368
376 pub fn writeSymtab(zig_got: ZigGotSection, elf_file: *Elf, ctx: anytype) !void {369 pub fn writeSymtab(zig_got: ZigGotSection, elf_file: *Elf, ctx: anytype) void {
377 const gpa = elf_file.base.allocator;
378 for (zig_got.entries.items, ctx.ilocal.., 0..) |entry, ilocal, index| {370 for (zig_got.entries.items, ctx.ilocal.., 0..) |entry, ilocal, index| {
379 const symbol = elf_file.symbol(entry);371 const symbol = elf_file.symbol(entry);
380 const symbol_name = symbol.name(elf_file);372 const symbol_name = symbol.name(elf_file);
381 const name = try std.fmt.allocPrint(gpa, "{s}$ziggot", .{symbol_name});373 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
382 defer gpa.free(name);374 elf_file.strtab.appendSliceAssumeCapacity(symbol_name);
383 const st_name = try elf_file.strtab.insert(gpa, name);375 elf_file.strtab.appendSliceAssumeCapacity("$ziggot");
376 elf_file.strtab.appendAssumeCapacity(0);
384 const st_value = zig_got.entryAddress(@intCast(index), elf_file);377 const st_value = zig_got.entryAddress(@intCast(index), elf_file);
385 const st_size = elf_file.archPtrWidthBytes();378 const st_size = elf_file.archPtrWidthBytes();
386 ctx.symtab[ilocal] = .{379 elf_file.symtab.items[ilocal] = .{
387 .st_name = st_name,380 .st_name = st_name,
388 .st_info = elf.STT_OBJECT,381 .st_info = elf.STT_OBJECT,
389 .st_other = 0,382 .st_other = 0,
...@@ -767,25 +760,17 @@ pub const GotSection = struct {...@@ -767,25 +760,17 @@ pub const GotSection = struct {
767 }760 }
768761
769 pub fn updateSymtabSize(got: *GotSection, elf_file: *Elf) void {762 pub fn updateSymtabSize(got: *GotSection, elf_file: *Elf) void {
770 _ = elf_file;
771 got.output_symtab_size.nlocals = @as(u32, @intCast(got.entries.items.len));763 got.output_symtab_size.nlocals = @as(u32, @intCast(got.entries.items.len));
772 }
773
774 pub fn updateStrtab(got: GotSection, elf_file: *Elf) !void {
775 const gpa = elf_file.base.allocator;
776 for (got.entries.items) |entry| {764 for (got.entries.items) |entry| {
777 const symbol_name = switch (entry.tag) {765 const symbol_name = switch (entry.tag) {
778 .tlsld => "",766 .tlsld => "",
779 inline else => elf_file.symbol(entry.symbol_index).name(elf_file),767 inline else => elf_file.symbol(entry.symbol_index).name(elf_file),
780 };768 };
781 const name = try std.fmt.allocPrint(gpa, "{s}${s}", .{ symbol_name, @tagName(entry.tag) });769 got.output_symtab_size.strsize += @as(u32, @intCast(symbol_name.len + @tagName(entry.tag).len)) + 1 + 1;
782 defer gpa.free(name);
783 _ = try elf_file.strtab.insert(gpa, name);
784 }770 }
785 }771 }
786772
787 pub fn writeSymtab(got: GotSection, elf_file: *Elf, ctx: anytype) !void {773 pub fn writeSymtab(got: GotSection, elf_file: *Elf, ctx: anytype) void {
788 const gpa = elf_file.base.allocator;
789 for (got.entries.items, ctx.ilocal..) |entry, ilocal| {774 for (got.entries.items, ctx.ilocal..) |entry, ilocal| {
790 const symbol = switch (entry.tag) {775 const symbol = switch (entry.tag) {
791 .tlsld => null,776 .tlsld => null,
...@@ -795,12 +780,14 @@ pub const GotSection = struct {...@@ -795,12 +780,14 @@ pub const GotSection = struct {
795 .tlsld => "",780 .tlsld => "",
796 inline else => symbol.?.name(elf_file),781 inline else => symbol.?.name(elf_file),
797 };782 };
798 const name = try std.fmt.allocPrint(gpa, "{s}${s}", .{ symbol_name, @tagName(entry.tag) });783 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
799 defer gpa.free(name);784 elf_file.strtab.appendSliceAssumeCapacity(symbol_name);
800 const st_name = try elf_file.strtab.insert(gpa, name);785 elf_file.strtab.appendAssumeCapacity('$');
786 elf_file.strtab.appendSliceAssumeCapacity(@tagName(entry.tag));
787 elf_file.strtab.appendAssumeCapacity(0);
801 const st_value = entry.address(elf_file);788 const st_value = entry.address(elf_file);
802 const st_size: u64 = entry.len() * elf_file.archPtrWidthBytes();789 const st_size: u64 = entry.len() * elf_file.archPtrWidthBytes();
803 ctx.symtab[ilocal] = .{790 elf_file.symtab.items[ilocal] = .{
804 .st_name = st_name,791 .st_name = st_name,
805 .st_info = elf.STT_OBJECT,792 .st_info = elf.STT_OBJECT,
806 .st_other = 0,793 .st_other = 0,
...@@ -922,30 +909,22 @@ pub const PltSection = struct {...@@ -922,30 +909,22 @@ pub const PltSection = struct {
922 }909 }
923910
924 pub fn updateSymtabSize(plt: *PltSection, elf_file: *Elf) void {911 pub fn updateSymtabSize(plt: *PltSection, elf_file: *Elf) void {
925 _ = elf_file;
926 plt.output_symtab_size.nlocals = @as(u32, @intCast(plt.symbols.items.len));912 plt.output_symtab_size.nlocals = @as(u32, @intCast(plt.symbols.items.len));
927 }
928
929 pub fn updateStrtab(plt: PltSection, elf_file: *Elf) !void {
930 const gpa = elf_file.base.allocator;
931 for (plt.symbols.items) |sym_index| {913 for (plt.symbols.items) |sym_index| {
932 const sym = elf_file.symbol(sym_index);914 const name = elf_file.symbol(sym_index).name(elf_file);
933 const name = try std.fmt.allocPrint(gpa, "{s}$plt", .{sym.name(elf_file)});915 plt.output_symtab_size.strsize += @as(u32, @intCast(name.len + "$plt".len)) + 1;
934 defer gpa.free(name);
935 _ = try elf_file.strtab.insert(gpa, name);
936 }916 }
937 }917 }
938918
939 pub fn writeSymtab(plt: PltSection, elf_file: *Elf, ctx: anytype) !void {919 pub fn writeSymtab(plt: PltSection, elf_file: *Elf, ctx: anytype) void {
940 const gpa = elf_file.base.allocator;
941
942 var ilocal = ctx.ilocal;920 var ilocal = ctx.ilocal;
943 for (plt.symbols.items) |sym_index| {921 for (plt.symbols.items) |sym_index| {
944 const sym = elf_file.symbol(sym_index);922 const sym = elf_file.symbol(sym_index);
945 const name = try std.fmt.allocPrint(gpa, "{s}$plt", .{sym.name(elf_file)});923 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
946 defer gpa.free(name);924 elf_file.strtab.appendSliceAssumeCapacity(sym.name(elf_file));
947 const st_name = try elf_file.strtab.insert(gpa, name);925 elf_file.strtab.appendSliceAssumeCapacity("$plt");
948 ctx.symtab[ilocal] = .{926 elf_file.strtab.appendAssumeCapacity(0);
927 elf_file.symtab.items[ilocal] = .{
949 .st_name = st_name,928 .st_name = st_name,
950 .st_info = elf.STT_FUNC,929 .st_info = elf.STT_FUNC,
951 .st_other = 0,930 .st_other = 0,
...@@ -1029,29 +1008,22 @@ pub const PltGotSection = struct {...@@ -1029,29 +1008,22 @@ pub const PltGotSection = struct {
1029 }1008 }
10301009
1031 pub fn updateSymtabSize(plt_got: *PltGotSection, elf_file: *Elf) void {1010 pub fn updateSymtabSize(plt_got: *PltGotSection, elf_file: *Elf) void {
1032 _ = elf_file;
1033 plt_got.output_symtab_size.nlocals = @as(u32, @intCast(plt_got.symbols.items.len));1011 plt_got.output_symtab_size.nlocals = @as(u32, @intCast(plt_got.symbols.items.len));
1034 }
1035
1036 pub fn updateStrtab(plt_got: PltGotSection, elf_file: *Elf) !void {
1037 const gpa = elf_file.base.allocator;
1038 for (plt_got.symbols.items) |sym_index| {1012 for (plt_got.symbols.items) |sym_index| {
1039 const sym = elf_file.symbol(sym_index);1013 const name = elf_file.symbol(sym_index).name(elf_file);
1040 const name = try std.fmt.allocPrint(gpa, "{s}$pltgot", .{sym.name(elf_file)});1014 plt_got.output_symtab_size.strsize += @as(u32, @intCast(name.len + "$pltgot".len)) + 1;
1041 defer gpa.free(name);
1042 _ = try elf_file.strtab.insert(gpa, name);
1043 }1015 }
1044 }1016 }
10451017
1046 pub fn writeSymtab(plt_got: PltGotSection, elf_file: *Elf, ctx: anytype) !void {1018 pub fn writeSymtab(plt_got: PltGotSection, elf_file: *Elf, ctx: anytype) void {
1047 const gpa = elf_file.base.allocator;
1048 var ilocal = ctx.ilocal;1019 var ilocal = ctx.ilocal;
1049 for (plt_got.symbols.items) |sym_index| {1020 for (plt_got.symbols.items) |sym_index| {
1050 const sym = elf_file.symbol(sym_index);1021 const sym = elf_file.symbol(sym_index);
1051 const name = try std.fmt.allocPrint(gpa, "{s}$pltgot", .{sym.name(elf_file)});1022 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
1052 defer gpa.free(name);1023 elf_file.strtab.appendSliceAssumeCapacity(sym.name(elf_file));
1053 const st_name = try elf_file.strtab.insert(gpa, name);1024 elf_file.strtab.appendSliceAssumeCapacity("$pltgot");
1054 ctx.symtab[ilocal] = .{1025 elf_file.strtab.appendAssumeCapacity(0);
1026 elf_file.symtab.items[ilocal] = .{
1055 .st_name = st_name,1027 .st_name = st_name,
1056 .st_info = elf.STT_FUNC,1028 .st_info = elf.STT_FUNC,
1057 .st_other = 0,1029 .st_other = 0,
...@@ -1166,7 +1138,7 @@ pub const DynsymSection = struct {...@@ -1166,7 +1138,7 @@ pub const DynsymSection = struct {
1166 new_extra.dynamic = index;1138 new_extra.dynamic = index;
1167 sym.setExtra(new_extra, elf_file);1139 sym.setExtra(new_extra, elf_file);
1168 } else try sym.addExtra(.{ .dynamic = index }, elf_file);1140 } else try sym.addExtra(.{ .dynamic = index }, elf_file);
1169 const off = try elf_file.dynstrtab.insert(gpa, sym.name(elf_file));1141 const off = try elf_file.insertDynString(sym.name(elf_file));
1170 try dynsym.entries.append(gpa, .{ .symbol_index = sym_index, .off = off });1142 try dynsym.entries.append(gpa, .{ .symbol_index = sym_index, .off = off });
1171 }1143 }
11721144
...@@ -1251,7 +1223,7 @@ pub const HashSection = struct {...@@ -1251,7 +1223,7 @@ pub const HashSection = struct {
1251 @memset(chains, 0);1223 @memset(chains, 0);
12521224
1253 for (elf_file.dynsym.entries.items, 1..) |entry, i| {1225 for (elf_file.dynsym.entries.items, 1..) |entry, i| {
1254 const name = elf_file.dynstrtab.getAssumeExists(entry.off);1226 const name = elf_file.getDynString(entry.off);
1255 const hash = hasher(name) % buckets.len;1227 const hash = hasher(name) % buckets.len;
1256 chains[@as(u32, @intCast(i))] = buckets[hash];1228 chains[@as(u32, @intCast(i))] = buckets[hash];
1257 buckets[hash] = @as(u32, @intCast(i));1229 buckets[hash] = @as(u32, @intCast(i));
...@@ -1490,7 +1462,7 @@ pub const VerneedSection = struct {...@@ -1490,7 +1462,7 @@ pub const VerneedSection = struct {
1490 sym.* = .{1462 sym.* = .{
1491 .vn_version = 1,1463 .vn_version = 1,
1492 .vn_cnt = 0,1464 .vn_cnt = 0,
1493 .vn_file = try elf_file.dynstrtab.insert(gpa, soname),1465 .vn_file = try elf_file.insertDynString(soname),
1494 .vn_aux = 0,1466 .vn_aux = 0,
1495 .vn_next = 0,1467 .vn_next = 0,
1496 };1468 };
...@@ -1509,7 +1481,7 @@ pub const VerneedSection = struct {...@@ -1509,7 +1481,7 @@ pub const VerneedSection = struct {
1509 .vna_hash = HashSection.hasher(version),1481 .vna_hash = HashSection.hasher(version),
1510 .vna_flags = 0,1482 .vna_flags = 0,
1511 .vna_other = vern.index,1483 .vna_other = vern.index,
1512 .vna_name = try elf_file.dynstrtab.insert(gpa, version),1484 .vna_name = try elf_file.insertDynString(version),
1513 .vna_next = 0,1485 .vna_next = 0,
1514 };1486 };
1515 verneed_sym.vn_cnt += 1;1487 verneed_sym.vn_cnt += 1;
src/link/MachO.zig+2-2
...@@ -58,7 +58,7 @@ globals_free_list: std.ArrayListUnmanaged(u32) = .{},...@@ -58,7 +58,7 @@ globals_free_list: std.ArrayListUnmanaged(u32) = .{},
58dyld_stub_binder_index: ?u32 = null,58dyld_stub_binder_index: ?u32 = null,
59dyld_private_atom_index: ?Atom.Index = null,59dyld_private_atom_index: ?Atom.Index = null,
6060
61strtab: StringTable(.strtab) = .{},61strtab: StringTable = .{},
6262
63got_table: TableSection(SymbolWithLoc) = .{},63got_table: TableSection(SymbolWithLoc) = .{},
64stub_table: TableSection(SymbolWithLoc) = .{},64stub_table: TableSection(SymbolWithLoc) = .{},
...@@ -5643,7 +5643,7 @@ const Module = @import("../Module.zig");...@@ -5643,7 +5643,7 @@ const Module = @import("../Module.zig");
5643const InternPool = @import("../InternPool.zig");5643const InternPool = @import("../InternPool.zig");
5644const Platform = load_commands.Platform;5644const Platform = load_commands.Platform;
5645const Relocation = @import("MachO/Relocation.zig");5645const Relocation = @import("MachO/Relocation.zig");
5646const StringTable = @import("strtab.zig").StringTable;5646const StringTable = @import("StringTable.zig");
5647const TableSection = @import("table_section.zig").TableSection;5647const TableSection = @import("table_section.zig").TableSection;
5648const Trie = @import("MachO/Trie.zig");5648const Trie = @import("MachO/Trie.zig");
5649const Type = @import("../type.zig").Type;5649const Type = @import("../type.zig").Type;
src/link/MachO/DebugSymbols.zig+2-2
...@@ -22,7 +22,7 @@ debug_aranges_section_dirty: bool = false,...@@ -22,7 +22,7 @@ debug_aranges_section_dirty: bool = false,
22debug_info_header_dirty: bool = false,22debug_info_header_dirty: bool = false,
23debug_line_header_dirty: bool = false,23debug_line_header_dirty: bool = false,
2424
25strtab: StringTable(.strtab) = .{},25strtab: StringTable = .{},
26relocs: std.ArrayListUnmanaged(Reloc) = .{},26relocs: std.ArrayListUnmanaged(Reloc) = .{},
2727
28pub const Reloc = struct {28pub const Reloc = struct {
...@@ -567,5 +567,5 @@ const Allocator = mem.Allocator;...@@ -567,5 +567,5 @@ const Allocator = mem.Allocator;
567const Dwarf = @import("../Dwarf.zig");567const Dwarf = @import("../Dwarf.zig");
568const MachO = @import("../MachO.zig");568const MachO = @import("../MachO.zig");
569const Module = @import("../../Module.zig");569const Module = @import("../../Module.zig");
570const StringTable = @import("../strtab.zig").StringTable;570const StringTable = @import("../StringTable.zig");
571const Type = @import("../../type.zig").Type;571const Type = @import("../../type.zig").Type;
src/link/MachO/zld.zig-1
...@@ -1227,7 +1227,6 @@ const LibStub = @import("../tapi.zig").LibStub;...@@ -1227,7 +1227,6 @@ const LibStub = @import("../tapi.zig").LibStub;
1227const Object = @import("Object.zig");1227const Object = @import("Object.zig");
1228const Platform = load_commands.Platform;1228const Platform = load_commands.Platform;
1229const Section = MachO.Section;1229const Section = MachO.Section;
1230const StringTable = @import("../strtab.zig").StringTable;
1231const SymbolWithLoc = MachO.SymbolWithLoc;1230const SymbolWithLoc = MachO.SymbolWithLoc;
1232const TableSection = @import("../table_section.zig").TableSection;1231const TableSection = @import("../table_section.zig").TableSection;
1233const Trie = @import("Trie.zig");1232const Trie = @import("Trie.zig");
src/link/StringTable.zig created+49
...@@ -0,0 +1,49 @@
1buffer: std.ArrayListUnmanaged(u8) = .{},
2table: std.HashMapUnmanaged(u32, void, StringIndexContext, std.hash_map.default_max_load_percentage) = .{},
3
4pub fn deinit(self: *Self, gpa: Allocator) void {
5 self.buffer.deinit(gpa);
6 self.table.deinit(gpa);
7}
8
9pub fn insert(self: *Self, gpa: Allocator, string: []const u8) !u32 {
10 const gop = try self.table.getOrPutContextAdapted(gpa, @as([]const u8, string), StringIndexAdapter{
11 .bytes = &self.buffer,
12 }, StringIndexContext{
13 .bytes = &self.buffer,
14 });
15 if (gop.found_existing) return gop.key_ptr.*;
16
17 try self.buffer.ensureUnusedCapacity(gpa, string.len + 1);
18 const new_off = @as(u32, @intCast(self.buffer.items.len));
19
20 self.buffer.appendSliceAssumeCapacity(string);
21 self.buffer.appendAssumeCapacity(0);
22
23 gop.key_ptr.* = new_off;
24
25 return new_off;
26}
27
28pub fn getOffset(self: *Self, string: []const u8) ?u32 {
29 return self.table.getKeyAdapted(string, StringIndexAdapter{
30 .bytes = &self.buffer,
31 });
32}
33
34pub fn get(self: Self, off: u32) ?[:0]const u8 {
35 if (off >= self.buffer.items.len) return null;
36 return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.buffer.items.ptr + off)), 0);
37}
38
39pub fn getAssumeExists(self: Self, off: u32) [:0]const u8 {
40 return self.get(off) orelse unreachable;
41}
42
43const std = @import("std");
44const mem = std.mem;
45
46const Allocator = mem.Allocator;
47const Self = @This();
48const StringIndexAdapter = std.hash_map.StringIndexAdapter;
49const StringIndexContext = std.hash_map.StringIndexContext;
src/link/strtab.zig deleted-121
...@@ -1,121 +0,0 @@
1const std = @import("std");
2const mem = std.mem;
3
4const Allocator = mem.Allocator;
5const StringIndexAdapter = std.hash_map.StringIndexAdapter;
6const StringIndexContext = std.hash_map.StringIndexContext;
7
8pub fn StringTable(comptime log_scope: @Type(.EnumLiteral)) type {
9 return struct {
10 const Self = @This();
11
12 const log = std.log.scoped(log_scope);
13
14 buffer: std.ArrayListUnmanaged(u8) = .{},
15 table: std.HashMapUnmanaged(u32, bool, StringIndexContext, std.hash_map.default_max_load_percentage) = .{},
16
17 pub fn deinit(self: *Self, gpa: Allocator) void {
18 self.buffer.deinit(gpa);
19 self.table.deinit(gpa);
20 }
21
22 pub fn toOwnedSlice(self: *Self, gpa: Allocator) []const u8 {
23 const result = self.buffer.toOwnedSlice(gpa);
24 self.table.clearRetainingCapacity();
25 return result;
26 }
27
28 pub const PrunedResult = struct {
29 buffer: []const u8,
30 idx_map: std.AutoHashMap(u32, u32),
31 };
32
33 pub fn toPrunedResult(self: *Self, gpa: Allocator) !PrunedResult {
34 var buffer = std.ArrayList(u8).init(gpa);
35 defer buffer.deinit();
36 try buffer.ensureTotalCapacity(self.buffer.items.len);
37 buffer.appendAssumeCapacity(0);
38
39 var idx_map = std.AutoHashMap(u32, u32).init(gpa);
40 errdefer idx_map.deinit();
41 try idx_map.ensureTotalCapacity(self.table.count());
42
43 var it = self.table.iterator();
44 while (it.next()) |entry| {
45 const off = entry.key_ptr.*;
46 const save = entry.value_ptr.*;
47 if (!save) continue;
48 const new_off = @as(u32, @intCast(buffer.items.len));
49 buffer.appendSliceAssumeCapacity(self.getAssumeExists(off));
50 idx_map.putAssumeCapacityNoClobber(off, new_off);
51 }
52
53 self.buffer.clearRetainingCapacity();
54 self.table.clearRetainingCapacity();
55
56 return PrunedResult{
57 .buffer = buffer.toOwnedSlice(),
58 .idx_map = idx_map,
59 };
60 }
61
62 pub fn insert(self: *Self, gpa: Allocator, string: []const u8) !u32 {
63 const gop = try self.table.getOrPutContextAdapted(gpa, @as([]const u8, string), StringIndexAdapter{
64 .bytes = &self.buffer,
65 }, StringIndexContext{
66 .bytes = &self.buffer,
67 });
68 if (gop.found_existing) {
69 const off = gop.key_ptr.*;
70 gop.value_ptr.* = true;
71 log.debug("reusing string '{s}' at offset 0x{x}", .{ string, off });
72 return off;
73 }
74
75 try self.buffer.ensureUnusedCapacity(gpa, string.len + 1);
76 const new_off = @as(u32, @intCast(self.buffer.items.len));
77
78 log.debug("writing new string '{s}' at offset 0x{x}", .{ string, new_off });
79
80 self.buffer.appendSliceAssumeCapacity(string);
81 self.buffer.appendAssumeCapacity(0);
82
83 gop.key_ptr.* = new_off;
84 gop.value_ptr.* = true;
85
86 return new_off;
87 }
88
89 pub fn delete(self: *Self, string: []const u8) void {
90 const value_ptr = self.table.getPtrAdapted(@as([]const u8, string), StringIndexAdapter{
91 .bytes = &self.buffer,
92 }) orelse return;
93 value_ptr.* = false;
94 log.debug("marked '{s}' for deletion", .{string});
95 }
96
97 pub fn getOffset(self: *Self, string: []const u8) ?u32 {
98 return self.table.getKeyAdapted(string, StringIndexAdapter{
99 .bytes = &self.buffer,
100 });
101 }
102
103 pub fn get(self: Self, off: u32) ?[:0]const u8 {
104 log.debug("getting string at 0x{x}", .{off});
105 if (off >= self.buffer.items.len) return null;
106 return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.buffer.items.ptr + off)), 0);
107 }
108
109 pub fn getAssumeExists(self: Self, off: u32) [:0]const u8 {
110 return self.get(off) orelse unreachable;
111 }
112
113 pub fn items(self: Self) []const u8 {
114 return self.buffer.items;
115 }
116
117 pub fn len(self: Self) usize {
118 return self.buffer.items.len;
119 }
120 };
121}
test/link/elf.zig+183-5
...@@ -6,9 +6,13 @@ pub fn build(b: *Build) void {...@@ -6,9 +6,13 @@ pub fn build(b: *Build) void {
6 const elf_step = b.step("test-elf", "Run ELF tests");6 const elf_step = b.step("test-elf", "Run ELF tests");
7 b.default_step = elf_step;7 b.default_step = elf_step;
88
9 const musl_target = CrossTarget{9 const default_target = CrossTarget{
10 .cpu_arch = .x86_64, // TODO relax this once ELF linker is able to handle other archs10 .cpu_arch = .x86_64, // TODO relax this once ELF linker is able to handle other archs
11 .os_tag = .linux,11 .os_tag = .linux,
12 };
13 const musl_target = CrossTarget{
14 .cpu_arch = .x86_64,
15 .os_tag = .linux,
12 .abi = .musl,16 .abi = .musl,
13 };17 };
14 const glibc_target = CrossTarget{18 const glibc_target = CrossTarget{
...@@ -18,7 +22,10 @@ pub fn build(b: *Build) void {...@@ -18,7 +22,10 @@ pub fn build(b: *Build) void {
18 };22 };
1923
20 // Exercise linker with self-hosted backend (no LLVM)24 // Exercise linker with self-hosted backend (no LLVM)
21 elf_step.dependOn(testLinkingZig(b, .{ .use_llvm = false }));25 elf_step.dependOn(testGcSectionsZig(b, .{ .use_llvm = false, .target = default_target }));
26 elf_step.dependOn(testLinkingObj(b, .{ .use_llvm = false, .target = default_target }));
27 elf_step.dependOn(testLinkingStaticLib(b, .{ .use_llvm = false, .target = default_target }));
28 elf_step.dependOn(testLinkingZig(b, .{ .use_llvm = false, .target = default_target }));
22 elf_step.dependOn(testImportingDataDynamic(b, .{ .use_llvm = false, .target = glibc_target }));29 elf_step.dependOn(testImportingDataDynamic(b, .{ .use_llvm = false, .target = glibc_target }));
23 elf_step.dependOn(testImportingDataStatic(b, .{ .use_llvm = false, .target = musl_target }));30 elf_step.dependOn(testImportingDataStatic(b, .{ .use_llvm = false, .target = musl_target }));
2431
...@@ -876,6 +883,110 @@ fn testGcSections(b: *Build, opts: Options) *Step {...@@ -876,6 +883,110 @@ fn testGcSections(b: *Build, opts: Options) *Step {
876 return test_step;883 return test_step;
877}884}
878885
886fn testGcSectionsZig(b: *Build, opts: Options) *Step {
887 const test_step = addTestStep(b, "gc-sections-zig", opts);
888
889 const obj = addObject(b, "obj", .{
890 .target = opts.target,
891 .use_llvm = true,
892 .use_lld = true,
893 });
894 addCSourceBytes(obj,
895 \\int live_var1 = 1;
896 \\int live_var2 = 2;
897 \\int dead_var1 = 3;
898 \\int dead_var2 = 4;
899 \\void live_fn1() {}
900 \\void live_fn2() { live_fn1(); }
901 \\void dead_fn1() {}
902 \\void dead_fn2() { dead_fn1(); }
903 , &.{});
904 obj.link_function_sections = true;
905 obj.link_data_sections = true;
906
907 {
908 const exe = addExecutable(b, "test1", opts);
909 addZigSourceBytes(exe,
910 \\const std = @import("std");
911 \\extern var live_var1: i32;
912 \\extern var live_var2: i32;
913 \\extern fn live_fn2() void;
914 \\pub fn main() void {
915 \\ const stdout = std.io.getStdOut();
916 \\ stdout.writer().print("{d} {d}\n", .{ live_var1, live_var2 }) catch unreachable;
917 \\ live_fn2();
918 \\}
919 );
920 exe.addObject(obj);
921 exe.link_gc_sections = false;
922
923 const run = addRunArtifact(exe);
924 run.expectStdOutEqual("1 2\n");
925 test_step.dependOn(&run.step);
926
927 const check = exe.checkObject();
928 check.checkInSymtab();
929 check.checkContains("live_var1");
930 check.checkInSymtab();
931 check.checkContains("live_var2");
932 check.checkInSymtab();
933 check.checkContains("dead_var1");
934 check.checkInSymtab();
935 check.checkContains("dead_var2");
936 check.checkInSymtab();
937 check.checkContains("live_fn1");
938 check.checkInSymtab();
939 check.checkContains("live_fn2");
940 check.checkInSymtab();
941 check.checkContains("dead_fn1");
942 check.checkInSymtab();
943 check.checkContains("dead_fn2");
944 test_step.dependOn(&check.step);
945 }
946
947 {
948 const exe = addExecutable(b, "test2", opts);
949 addZigSourceBytes(exe,
950 \\const std = @import("std");
951 \\extern var live_var1: i32;
952 \\extern var live_var2: i32;
953 \\extern fn live_fn2() void;
954 \\pub fn main() void {
955 \\ const stdout = std.io.getStdOut();
956 \\ stdout.writer().print("{d} {d}\n", .{ live_var1, live_var2 }) catch unreachable;
957 \\ live_fn2();
958 \\}
959 );
960 exe.addObject(obj);
961 exe.link_gc_sections = true;
962
963 const run = addRunArtifact(exe);
964 run.expectStdOutEqual("1 2\n");
965 test_step.dependOn(&run.step);
966
967 const check = exe.checkObject();
968 check.checkInSymtab();
969 check.checkContains("live_var1");
970 check.checkInSymtab();
971 check.checkContains("live_var2");
972 check.checkInSymtab();
973 check.checkNotPresent("dead_var1");
974 check.checkInSymtab();
975 check.checkNotPresent("dead_var2");
976 check.checkInSymtab();
977 check.checkContains("live_fn1");
978 check.checkInSymtab();
979 check.checkContains("live_fn2");
980 check.checkInSymtab();
981 check.checkNotPresent("dead_fn1");
982 check.checkInSymtab();
983 check.checkNotPresent("dead_fn2");
984 test_step.dependOn(&check.step);
985 }
986
987 return test_step;
988}
989
879fn testHiddenWeakUndef(b: *Build, opts: Options) *Step {990fn testHiddenWeakUndef(b: *Build, opts: Options) *Step {
880 const test_step = addTestStep(b, "hidden-weak-undef", opts);991 const test_step = addTestStep(b, "hidden-weak-undef", opts);
881992
...@@ -1714,6 +1825,72 @@ fn testLinkingCpp(b: *Build, opts: Options) *Step {...@@ -1714,6 +1825,72 @@ fn testLinkingCpp(b: *Build, opts: Options) *Step {
1714 return test_step;1825 return test_step;
1715}1826}
17161827
1828fn testLinkingObj(b: *Build, opts: Options) *Step {
1829 const test_step = addTestStep(b, "linking-obj", opts);
1830
1831 const obj = addObject(b, "aobj", opts);
1832 addZigSourceBytes(obj,
1833 \\extern var mod: usize;
1834 \\export fn callMe() usize {
1835 \\ return me * mod;
1836 \\}
1837 \\var me: usize = 42;
1838 );
1839
1840 const exe = addExecutable(b, "testobj", opts);
1841 addZigSourceBytes(exe,
1842 \\const std = @import("std");
1843 \\extern fn callMe() usize;
1844 \\export var mod: usize = 2;
1845 \\pub fn main() void {
1846 \\ std.debug.print("{d}\n", .{callMe()});
1847 \\}
1848 );
1849 exe.addObject(obj);
1850
1851 const run = addRunArtifact(exe);
1852 run.expectStdErrEqual("84\n");
1853 test_step.dependOn(&run.step);
1854
1855 return test_step;
1856}
1857
1858fn testLinkingStaticLib(b: *Build, opts: Options) *Step {
1859 const test_step = addTestStep(b, "linking-static-lib", opts);
1860
1861 const lib = b.addStaticLibrary(.{
1862 .name = "alib",
1863 .target = opts.target,
1864 .optimize = opts.optimize,
1865 .use_llvm = opts.use_llvm,
1866 .use_lld = false,
1867 });
1868 addZigSourceBytes(lib,
1869 \\extern var mod: usize;
1870 \\export fn callMe() usize {
1871 \\ return me * mod;
1872 \\}
1873 \\var me: usize = 42;
1874 );
1875
1876 const exe = addExecutable(b, "testlib", opts);
1877 addZigSourceBytes(exe,
1878 \\const std = @import("std");
1879 \\extern fn callMe() usize;
1880 \\export var mod: usize = 2;
1881 \\pub fn main() void {
1882 \\ std.debug.print("{d}\n", .{callMe()});
1883 \\}
1884 );
1885 exe.linkLibrary(lib);
1886
1887 const run = addRunArtifact(exe);
1888 run.expectStdErrEqual("84\n");
1889 test_step.dependOn(&run.step);
1890
1891 return test_step;
1892}
1893
1717fn testLinkingZig(b: *Build, opts: Options) *Step {1894fn testLinkingZig(b: *Build, opts: Options) *Step {
1718 const test_step = addTestStep(b, "linking-zig-static", opts);1895 const test_step = addTestStep(b, "linking-zig-static", opts);
17191896
...@@ -3114,6 +3291,7 @@ const Options = struct {...@@ -3114,6 +3291,7 @@ const Options = struct {
3114 target: CrossTarget = .{ .cpu_arch = .x86_64, .os_tag = .linux },3291 target: CrossTarget = .{ .cpu_arch = .x86_64, .os_tag = .linux },
3115 optimize: std.builtin.OptimizeMode = .Debug,3292 optimize: std.builtin.OptimizeMode = .Debug,
3116 use_llvm: bool = true,3293 use_llvm: bool = true,
3294 use_lld: bool = false,
3117};3295};
31183296
3119fn addTestStep(b: *Build, comptime prefix: []const u8, opts: Options) *Step {3297fn addTestStep(b: *Build, comptime prefix: []const u8, opts: Options) *Step {
...@@ -3134,7 +3312,7 @@ fn addExecutable(b: *Build, name: []const u8, opts: Options) *Compile {...@@ -3134,7 +3312,7 @@ fn addExecutable(b: *Build, name: []const u8, opts: Options) *Compile {
3134 .target = opts.target,3312 .target = opts.target,
3135 .optimize = opts.optimize,3313 .optimize = opts.optimize,
3136 .use_llvm = opts.use_llvm,3314 .use_llvm = opts.use_llvm,
3137 .use_lld = false,3315 .use_lld = opts.use_lld,
3138 });3316 });
3139}3317}
31403318
...@@ -3144,7 +3322,7 @@ fn addObject(b: *Build, name: []const u8, opts: Options) *Compile {...@@ -3144,7 +3322,7 @@ fn addObject(b: *Build, name: []const u8, opts: Options) *Compile {
3144 .target = opts.target,3322 .target = opts.target,
3145 .optimize = opts.optimize,3323 .optimize = opts.optimize,
3146 .use_llvm = opts.use_llvm,3324 .use_llvm = opts.use_llvm,
3147 .use_lld = false,3325 .use_lld = opts.use_lld,
3148 });3326 });
3149}3327}
31503328
...@@ -3164,7 +3342,7 @@ fn addSharedLibrary(b: *Build, name: []const u8, opts: Options) *Compile {...@@ -3164,7 +3342,7 @@ fn addSharedLibrary(b: *Build, name: []const u8, opts: Options) *Compile {
3164 .target = opts.target,3342 .target = opts.target,
3165 .optimize = opts.optimize,3343 .optimize = opts.optimize,
3166 .use_llvm = opts.use_llvm,3344 .use_llvm = opts.use_llvm,
3167 .use_lld = false,3345 .use_lld = opts.use_lld,
3168 });3346 });
3169}3347}
31703348