authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-08-08 00:27:36+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-08-08 00:27:36+02:00
logcfe6ff4301d43ccd2739b2f4495e371211252afd
tree065a3fcfb21e8d3d986be2e5779a2ef43ee7ef78
parentb8705ed6527e779a140e8beccb48d424dbbdf856
parentb058545970efb6f533f9930d23af2a6d0c6ce9c3
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #20971 from ziglang/elf-ownership-2

elf: move ownership of symbols into owning objects

22 files changed, 1607 insertions(+), 1229 deletions(-)

src/arch/aarch64/CodeGen.zig+3-2
...@@ -4354,8 +4354,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -4354,8 +4354,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
4354 if (try self.air.value(callee, pt)) |func_value| {4354 if (try self.air.value(callee, pt)) |func_value| {
4355 if (func_value.getFunction(mod)) |func| {4355 if (func_value.getFunction(mod)) |func| {
4356 if (self.bin_file.cast(link.File.Elf)) |elf_file| {4356 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
4357 const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func.owner_decl);4357 const zo = elf_file.zigObjectPtr().?;
4358 const sym = elf_file.symbol(sym_index);4358 const sym_index = try zo.getOrCreateMetadataForDecl(elf_file, func.owner_decl);
4359 const sym = zo.symbol(sym_index);
4359 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);4360 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
4360 const got_addr = @as(u32, @intCast(sym.zigGotAddress(elf_file)));4361 const got_addr = @as(u32, @intCast(sym.zigGotAddress(elf_file)));
4361 try self.genSetReg(Type.usize, .x30, .{ .memory = got_addr });4362 try self.genSetReg(Type.usize, .x30, .{ .memory = got_addr });
src/arch/arm/CodeGen.zig+3-2
...@@ -4336,8 +4336,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -4336,8 +4336,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
4336 if (try self.air.value(callee, pt)) |func_value| {4336 if (try self.air.value(callee, pt)) |func_value| {
4337 if (func_value.getFunction(mod)) |func| {4337 if (func_value.getFunction(mod)) |func| {
4338 if (self.bin_file.cast(link.File.Elf)) |elf_file| {4338 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
4339 const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func.owner_decl);4339 const zo = elf_file.zigObjectPtr().?;
4340 const sym = elf_file.symbol(sym_index);4340 const sym_index = try zo.getOrCreateMetadataForDecl(elf_file, func.owner_decl);
4341 const sym = zo.symbol(sym_index);
4341 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);4342 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
4342 const got_addr: u32 = @intCast(sym.zigGotAddress(elf_file));4343 const got_addr: u32 = @intCast(sym.zigGotAddress(elf_file));
4343 try self.genSetReg(Type.usize, .lr, .{ .memory = got_addr });4344 try self.genSetReg(Type.usize, .lr, .{ .memory = got_addr });
src/arch/riscv64/CodeGen.zig+10-14
...@@ -1409,14 +1409,14 @@ fn genLazy(func: *Func, lazy_sym: link.File.LazySymbol) InnerError!void {...@@ -1409,14 +1409,14 @@ fn genLazy(func: *Func, lazy_sym: link.File.LazySymbol) InnerError!void {
1409 defer func.register_manager.unlockReg(data_lock);1409 defer func.register_manager.unlockReg(data_lock);
14101410
1411 const elf_file = func.bin_file.cast(link.File.Elf).?;1411 const elf_file = func.bin_file.cast(link.File.Elf).?;
1412 const sym_index = elf_file.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(elf_file, pt, .{1412 const zo = elf_file.zigObjectPtr().?;
1413 const sym_index = zo.getOrCreateMetadataForLazySymbol(elf_file, pt, .{
1413 .kind = .const_data,1414 .kind = .const_data,
1414 .ty = enum_ty,1415 .ty = enum_ty,
1415 }) catch |err|1416 }) catch |err|
1416 return func.fail("{s} creating lazy symbol", .{@errorName(err)});1417 return func.fail("{s} creating lazy symbol", .{@errorName(err)});
1417 const sym = elf_file.symbol(sym_index);
14181418
1419 try func.genSetReg(Type.u64, data_reg, .{ .lea_symbol = .{ .sym = sym.esym_index } });1419 try func.genSetReg(Type.u64, data_reg, .{ .lea_symbol = .{ .sym = sym_index } });
14201420
1421 const cmp_reg, const cmp_lock = try func.allocReg(.int);1421 const cmp_reg, const cmp_lock = try func.allocReg(.int);
1422 defer func.register_manager.unlockReg(cmp_lock);1422 defer func.register_manager.unlockReg(cmp_lock);
...@@ -4946,13 +4946,13 @@ fn genCall(...@@ -4946,13 +4946,13 @@ fn genCall(
4946 }) {4946 }) {
4947 .func => |func_val| {4947 .func => |func_val| {
4948 if (func.bin_file.cast(link.File.Elf)) |elf_file| {4948 if (func.bin_file.cast(link.File.Elf)) |elf_file| {
4949 const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func_val.owner_decl);4949 const zo = elf_file.zigObjectPtr().?;
4950 const sym = elf_file.symbol(sym_index);4950 const sym_index = try zo.getOrCreateMetadataForDecl(elf_file, func_val.owner_decl);
49514951
4952 if (func.mod.pic) {4952 if (func.mod.pic) {
4953 return func.fail("TODO: genCall pic", .{});4953 return func.fail("TODO: genCall pic", .{});
4954 } else {4954 } else {
4955 try func.genSetReg(Type.u64, .ra, .{ .load_symbol = .{ .sym = sym.esym_index } });4955 try func.genSetReg(Type.u64, .ra, .{ .load_symbol = .{ .sym = sym_index } });
4956 _ = try func.addInst(.{4956 _ = try func.addInst(.{
4957 .tag = .jalr,4957 .tag = .jalr,
4958 .data = .{ .i_type = .{4958 .data = .{ .i_type = .{
...@@ -7822,14 +7822,14 @@ fn airTagName(func: *Func, inst: Air.Inst.Index) !void {...@@ -7822,14 +7822,14 @@ fn airTagName(func: *Func, inst: Air.Inst.Index) !void {
78227822
7823 const lazy_sym = link.File.LazySymbol.initDecl(.code, enum_ty.getOwnerDecl(zcu), zcu);7823 const lazy_sym = link.File.LazySymbol.initDecl(.code, enum_ty.getOwnerDecl(zcu), zcu);
7824 const elf_file = func.bin_file.cast(link.File.Elf).?;7824 const elf_file = func.bin_file.cast(link.File.Elf).?;
7825 const sym_index = elf_file.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(elf_file, pt, lazy_sym) catch |err|7825 const zo = elf_file.zigObjectPtr().?;
7826 const sym_index = zo.getOrCreateMetadataForLazySymbol(elf_file, pt, lazy_sym) catch |err|
7826 return func.fail("{s} creating lazy symbol", .{@errorName(err)});7827 return func.fail("{s} creating lazy symbol", .{@errorName(err)});
7827 const sym = elf_file.symbol(sym_index);
78287828
7829 if (func.mod.pic) {7829 if (func.mod.pic) {
7830 return func.fail("TODO: airTagName pic", .{});7830 return func.fail("TODO: airTagName pic", .{});
7831 } else {7831 } else {
7832 try func.genSetReg(Type.u64, .ra, .{ .load_symbol = .{ .sym = sym.esym_index } });7832 try func.genSetReg(Type.u64, .ra, .{ .load_symbol = .{ .sym = sym_index } });
7833 _ = try func.addInst(.{7833 _ = try func.addInst(.{
7834 .tag = .jalr,7834 .tag = .jalr,
7835 .data = .{ .i_type = .{7835 .data = .{ .i_type = .{
...@@ -8047,11 +8047,7 @@ fn genTypedValue(func: *Func, val: Value) InnerError!MCValue {...@@ -8047,11 +8047,7 @@ fn genTypedValue(func: *Func, val: Value) InnerError!MCValue {
8047 return error.CodegenFail;8047 return error.CodegenFail;
8048 };8048 };
8049 switch (lf.tag) {8049 switch (lf.tag) {
8050 .elf => {8050 .elf => return MCValue{ .undef = local_sym_index },
8051 const elf_file = lf.cast(link.File.Elf).?;
8052 const local = elf_file.symbol(local_sym_index);
8053 return MCValue{ .undef = local.esym_index };
8054 },
8055 else => unreachable,8051 else => unreachable,
8056 }8052 }
8057 }8053 }
src/arch/riscv64/Emit.zig+8-6
...@@ -50,16 +50,16 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -50,16 +50,16 @@ pub fn emitMir(emit: *Emit) Error!void {
50 };50 };
5151
52 const elf_file = emit.bin_file.cast(link.File.Elf).?;52 const elf_file = emit.bin_file.cast(link.File.Elf).?;
53 const zo = elf_file.zigObjectPtr().?;
5354
54 const atom_ptr = elf_file.symbol(symbol.atom_index).atom(elf_file).?;55 const atom_ptr = zo.symbol(symbol.atom_index).atom(elf_file).?;
55 const sym_index = elf_file.zigObjectPtr().?.symbol(symbol.sym_index);56 const sym = zo.symbol(symbol.sym_index);
56 const sym = elf_file.symbol(sym_index);
5757
58 var hi_r_type: u32 = @intFromEnum(std.elf.R_RISCV.HI20);58 var hi_r_type: u32 = @intFromEnum(std.elf.R_RISCV.HI20);
59 var lo_r_type: u32 = @intFromEnum(std.elf.R_RISCV.LO12_I);59 var lo_r_type: u32 = @intFromEnum(std.elf.R_RISCV.LO12_I);
6060
61 if (sym.flags.needs_zig_got and !is_obj_or_static_lib) {61 if (sym.flags.needs_zig_got and !is_obj_or_static_lib) {
62 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);62 _ = try sym.getOrCreateZigGotEntry(symbol.sym_index, elf_file);
6363
64 hi_r_type = Elf.R_ZIG_GOT_HI20;64 hi_r_type = Elf.R_ZIG_GOT_HI20;
65 lo_r_type = Elf.R_ZIG_GOT_LO12;65 lo_r_type = Elf.R_ZIG_GOT_LO12;
...@@ -82,8 +82,9 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -82,8 +82,9 @@ pub fn emitMir(emit: *Emit) Error!void {
82 },82 },
83 .load_tlv_reloc => |symbol| {83 .load_tlv_reloc => |symbol| {
84 const elf_file = emit.bin_file.cast(link.File.Elf).?;84 const elf_file = emit.bin_file.cast(link.File.Elf).?;
85 const zo = elf_file.zigObjectPtr().?;
8586
86 const atom_ptr = elf_file.symbol(symbol.atom_index).atom(elf_file).?;87 const atom_ptr = zo.symbol(symbol.atom_index).atom(elf_file).?;
8788
88 const R_RISCV = std.elf.R_RISCV;89 const R_RISCV = std.elf.R_RISCV;
8990
...@@ -107,7 +108,8 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -107,7 +108,8 @@ pub fn emitMir(emit: *Emit) Error!void {
107 },108 },
108 .call_extern_fn_reloc => |symbol| {109 .call_extern_fn_reloc => |symbol| {
109 const elf_file = emit.bin_file.cast(link.File.Elf).?;110 const elf_file = emit.bin_file.cast(link.File.Elf).?;
110 const atom_ptr = elf_file.symbol(symbol.atom_index).atom(elf_file).?;111 const zo = elf_file.zigObjectPtr().?;
112 const atom_ptr = zo.symbol(symbol.atom_index).atom(elf_file).?;
111113
112 const r_type: u32 = @intFromEnum(std.elf.R_RISCV.CALL_PLT);114 const r_type: u32 = @intFromEnum(std.elf.R_RISCV.CALL_PLT);
113115
src/arch/sparc64/CodeGen.zig+3-2
...@@ -1354,8 +1354,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -1354,8 +1354,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
1354 switch (mod.intern_pool.indexToKey(func_value.ip_index)) {1354 switch (mod.intern_pool.indexToKey(func_value.ip_index)) {
1355 .func => |func| {1355 .func => |func| {
1356 const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: {1356 const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: {
1357 const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func.owner_decl);1357 const zo = elf_file.zigObjectPtr().?;
1358 const sym = elf_file.symbol(sym_index);1358 const sym_index = try zo.getOrCreateMetadataForDecl(elf_file, func.owner_decl);
1359 const sym = zo.symbol(sym_index);
1359 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);1360 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
1360 break :blk @as(u32, @intCast(sym.zigGotAddress(elf_file)));1361 break :blk @as(u32, @intCast(sym.zigGotAddress(elf_file)));
1361 } else unreachable;1362 } else unreachable;
src/arch/x86_64/CodeGen.zig+9-9
...@@ -12327,8 +12327,8 @@ fn genCall(self: *Self, info: union(enum) {...@@ -12327,8 +12327,8 @@ fn genCall(self: *Self, info: union(enum) {
12327 }) {12327 }) {
12328 .func => |func| {12328 .func => |func| {
12329 if (self.bin_file.cast(link.File.Elf)) |elf_file| {12329 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
12330 const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func.owner_decl);12330 const zo = elf_file.zigObjectPtr().?;
12331 const sym = elf_file.symbol(sym_index);12331 const sym_index = try zo.getOrCreateMetadataForDecl(elf_file, func.owner_decl);
12332 if (self.mod.pic) {12332 if (self.mod.pic) {
12333 const callee_reg: Register = switch (resolved_cc) {12333 const callee_reg: Register = switch (resolved_cc) {
12334 .SysV => callee: {12334 .SysV => callee: {
...@@ -12345,14 +12345,14 @@ fn genCall(self: *Self, info: union(enum) {...@@ -12345,14 +12345,14 @@ fn genCall(self: *Self, info: union(enum) {
12345 try self.genSetReg(12345 try self.genSetReg(
12346 callee_reg,12346 callee_reg,
12347 Type.usize,12347 Type.usize,
12348 .{ .load_symbol = .{ .sym = sym.esym_index } },12348 .{ .load_symbol = .{ .sym = sym_index } },
12349 .{},12349 .{},
12350 );12350 );
12351 try self.asmRegister(.{ ._, .call }, callee_reg);12351 try self.asmRegister(.{ ._, .call }, callee_reg);
12352 } else try self.asmMemory(.{ ._, .call }, .{12352 } else try self.asmMemory(.{ ._, .call }, .{
12353 .base = .{ .reloc = .{12353 .base = .{ .reloc = .{
12354 .atom_index = try self.owner.getSymbolIndex(self),12354 .atom_index = try self.owner.getSymbolIndex(self),
12355 .sym_index = sym.esym_index,12355 .sym_index = sym_index,
12356 } },12356 } },
12357 .mod = .{ .rm = .{ .size = .qword } },12357 .mod = .{ .rm = .{ .size = .qword } },
12358 });12358 });
...@@ -15320,16 +15320,16 @@ fn genLazySymbolRef(...@@ -15320,16 +15320,16 @@ fn genLazySymbolRef(
15320) InnerError!void {15320) InnerError!void {
15321 const pt = self.pt;15321 const pt = self.pt;
15322 if (self.bin_file.cast(link.File.Elf)) |elf_file| {15322 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
15323 const sym_index = elf_file.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(elf_file, pt, lazy_sym) catch |err|15323 const zo = elf_file.zigObjectPtr().?;
15324 const sym_index = zo.getOrCreateMetadataForLazySymbol(elf_file, pt, lazy_sym) catch |err|
15324 return self.fail("{s} creating lazy symbol", .{@errorName(err)});15325 return self.fail("{s} creating lazy symbol", .{@errorName(err)});
15325 const sym = elf_file.symbol(sym_index);
15326 if (self.mod.pic) {15326 if (self.mod.pic) {
15327 switch (tag) {15327 switch (tag) {
15328 .lea, .call => try self.genSetReg(reg, Type.usize, .{15328 .lea, .call => try self.genSetReg(reg, Type.usize, .{
15329 .load_symbol = .{ .sym = sym.esym_index },15329 .load_symbol = .{ .sym = sym_index },
15330 }, .{}),15330 }, .{}),
15331 .mov => try self.genSetReg(reg, Type.usize, .{15331 .mov => try self.genSetReg(reg, Type.usize, .{
15332 .load_symbol = .{ .sym = sym.esym_index },15332 .load_symbol = .{ .sym = sym_index },
15333 }, .{}),15333 }, .{}),
15334 else => unreachable,15334 else => unreachable,
15335 }15335 }
...@@ -15341,7 +15341,7 @@ fn genLazySymbolRef(...@@ -15341,7 +15341,7 @@ fn genLazySymbolRef(
15341 } else {15341 } else {
15342 const reloc = bits.Symbol{15342 const reloc = bits.Symbol{
15343 .atom_index = try self.owner.getSymbolIndex(self),15343 .atom_index = try self.owner.getSymbolIndex(self),
15344 .sym_index = sym.esym_index,15344 .sym_index = sym_index,
15345 };15345 };
15346 switch (tag) {15346 switch (tag) {
15347 .lea, .mov => try self.asmRegisterMemory(.{ ._, .mov }, reg.to64(), .{15347 .lea, .mov => try self.asmRegisterMemory(.{ ._, .mov }, reg.to64(), .{
src/arch/x86_64/Emit.zig+10-7
...@@ -42,7 +42,8 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -42,7 +42,8 @@ pub fn emitMir(emit: *Emit) Error!void {
42 }),42 }),
43 .linker_extern_fn => |symbol| if (emit.lower.bin_file.cast(link.File.Elf)) |elf_file| {43 .linker_extern_fn => |symbol| if (emit.lower.bin_file.cast(link.File.Elf)) |elf_file| {
44 // Add relocation to the decl.44 // Add relocation to the decl.
45 const atom_ptr = elf_file.symbol(symbol.atom_index).atom(elf_file).?;45 const zo = elf_file.zigObjectPtr().?;
46 const atom_ptr = zo.symbol(symbol.atom_index).atom(elf_file).?;
46 const r_type = @intFromEnum(std.elf.R_X86_64.PLT32);47 const r_type = @intFromEnum(std.elf.R_X86_64.PLT32);
47 try atom_ptr.addReloc(elf_file, .{48 try atom_ptr.addReloc(elf_file, .{
48 .r_offset = end_offset - 4,49 .r_offset = end_offset - 4,
...@@ -88,7 +89,8 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -88,7 +89,8 @@ pub fn emitMir(emit: *Emit) Error!void {
88 }),89 }),
89 .linker_tlsld => |data| {90 .linker_tlsld => |data| {
90 const elf_file = emit.lower.bin_file.cast(link.File.Elf).?;91 const elf_file = emit.lower.bin_file.cast(link.File.Elf).?;
91 const atom = elf_file.symbol(data.atom_index).atom(elf_file).?;92 const zo = elf_file.zigObjectPtr().?;
93 const atom = zo.symbol(data.atom_index).atom(elf_file).?;
92 const r_type = @intFromEnum(std.elf.R_X86_64.TLSLD);94 const r_type = @intFromEnum(std.elf.R_X86_64.TLSLD);
93 try atom.addReloc(elf_file, .{95 try atom.addReloc(elf_file, .{
94 .r_offset = end_offset - 4,96 .r_offset = end_offset - 4,
...@@ -98,7 +100,8 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -98,7 +100,8 @@ pub fn emitMir(emit: *Emit) Error!void {
98 },100 },
99 .linker_dtpoff => |data| {101 .linker_dtpoff => |data| {
100 const elf_file = emit.lower.bin_file.cast(link.File.Elf).?;102 const elf_file = emit.lower.bin_file.cast(link.File.Elf).?;
101 const atom = elf_file.symbol(data.atom_index).atom(elf_file).?;103 const zo = elf_file.zigObjectPtr().?;
104 const atom = zo.symbol(data.atom_index).atom(elf_file).?;
102 const r_type = @intFromEnum(std.elf.R_X86_64.DTPOFF32);105 const r_type = @intFromEnum(std.elf.R_X86_64.DTPOFF32);
103 try atom.addReloc(elf_file, .{106 try atom.addReloc(elf_file, .{
104 .r_offset = end_offset - 4,107 .r_offset = end_offset - 4,
...@@ -112,11 +115,11 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -112,11 +115,11 @@ pub fn emitMir(emit: *Emit) Error!void {
112 .Obj => true,115 .Obj => true,
113 .Lib => emit.lower.link_mode == .static,116 .Lib => emit.lower.link_mode == .static,
114 };117 };
115 const atom = elf_file.symbol(data.atom_index).atom(elf_file).?;118 const zo = elf_file.zigObjectPtr().?;
116 const sym_index = elf_file.zigObjectPtr().?.symbol(data.sym_index);119 const atom = zo.symbol(data.atom_index).atom(elf_file).?;
117 const sym = elf_file.symbol(sym_index);120 const sym = zo.symbol(data.sym_index);
118 if (sym.flags.needs_zig_got and !is_obj_or_static_lib) {121 if (sym.flags.needs_zig_got and !is_obj_or_static_lib) {
119 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);122 _ = try sym.getOrCreateZigGotEntry(data.sym_index, elf_file);
120 }123 }
121 if (emit.lower.pic) {124 if (emit.lower.pic) {
122 const r_type: u32 = if (sym.flags.needs_zig_got and !is_obj_or_static_lib)125 const r_type: u32 = if (sym.flags.needs_zig_got and !is_obj_or_static_lib)
src/arch/x86_64/Lower.zig+2-2
...@@ -349,8 +349,8 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)...@@ -349,8 +349,8 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
349 assert(mem_op.sib.scale_index.scale == 0);349 assert(mem_op.sib.scale_index.scale == 0);
350350
351 if (lower.bin_file.cast(link.File.Elf)) |elf_file| {351 if (lower.bin_file.cast(link.File.Elf)) |elf_file| {
352 const sym_index = elf_file.zigObjectPtr().?.symbol(sym.sym_index);352 const zo = elf_file.zigObjectPtr().?;
353 const elf_sym = elf_file.symbol(sym_index);353 const elf_sym = zo.symbol(sym.sym_index);
354354
355 if (elf_sym.flags.is_tls) {355 if (elf_sym.flags.is_tls) {
356 // TODO handle extern TLS vars, i.e., emit GD model356 // TODO handle extern TLS vars, i.e., emit GD model
src/codegen.zig+6-8
...@@ -906,20 +906,20 @@ fn genDeclRef(...@@ -906,20 +906,20 @@ fn genDeclRef(
906 const is_extern = decl.isExtern(zcu);906 const is_extern = decl.isExtern(zcu);
907907
908 if (lf.cast(link.File.Elf)) |elf_file| {908 if (lf.cast(link.File.Elf)) |elf_file| {
909 const zo = elf_file.zigObjectPtr().?;
909 if (is_extern) {910 if (is_extern) {
910 const name = decl.name.toSlice(ip);911 const name = decl.name.toSlice(ip);
911 // TODO audit this912 // TODO audit this
912 const lib_name = if (decl.getOwnedVariable(zcu)) |ov| ov.lib_name.toSlice(ip) else null;913 const lib_name = if (decl.getOwnedVariable(zcu)) |ov| ov.lib_name.toSlice(ip) else null;
913 const sym_index = try elf_file.getGlobalSymbol(name, lib_name);914 const sym_index = try elf_file.getGlobalSymbol(name, lib_name);
914 elf_file.symbol(elf_file.zigObjectPtr().?.symbol(sym_index)).flags.needs_got = true;915 zo.symbol(sym_index).flags.needs_got = true;
915 return GenResult.mcv(.{ .load_symbol = sym_index });916 return GenResult.mcv(.{ .load_symbol = sym_index });
916 }917 }
917 const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, decl_index);918 const sym_index = try zo.getOrCreateMetadataForDecl(elf_file, decl_index);
918 const sym = elf_file.symbol(sym_index);
919 if (is_threadlocal) {919 if (is_threadlocal) {
920 return GenResult.mcv(.{ .load_tlv = sym.esym_index });920 return GenResult.mcv(.{ .load_tlv = sym_index });
921 }921 }
922 return GenResult.mcv(.{ .load_symbol = sym.esym_index });922 return GenResult.mcv(.{ .load_symbol = sym_index });
923 } else if (lf.cast(link.File.MachO)) |macho_file| {923 } else if (lf.cast(link.File.MachO)) |macho_file| {
924 const zo = macho_file.getZigObject().?;924 const zo = macho_file.getZigObject().?;
925 if (is_extern) {925 if (is_extern) {
...@@ -971,9 +971,7 @@ fn genUnnamedConst(...@@ -971,9 +971,7 @@ fn genUnnamedConst(
971 };971 };
972 switch (lf.tag) {972 switch (lf.tag) {
973 .elf => {973 .elf => {
974 const elf_file = lf.cast(link.File.Elf).?;974 return GenResult.mcv(.{ .load_symbol = local_sym_index });
975 const local = elf_file.symbol(local_sym_index);
976 return GenResult.mcv(.{ .load_symbol = local.esym_index });
977 },975 },
978 .macho => {976 .macho => {
979 const macho_file = lf.cast(link.File.MachO).?;977 const macho_file = lf.cast(link.File.MachO).?;
src/link/Elf.zig+186-249
...@@ -173,12 +173,7 @@ shstrtab_section_index: ?u32 = null,...@@ -173,12 +173,7 @@ shstrtab_section_index: ?u32 = null,
173strtab_section_index: ?u32 = null,173strtab_section_index: ?u32 = null,
174symtab_section_index: ?u32 = null,174symtab_section_index: ?u32 = null,
175175
176/// An array of symbols parsed across all input files.176resolver: SymbolResolver = .{},
177symbols: std.ArrayListUnmanaged(Symbol) = .{},
178symbols_extra: std.ArrayListUnmanaged(u32) = .{},
179symbols_free_list: std.ArrayListUnmanaged(Symbol.Index) = .{},
180
181resolver: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index) = .{},
182177
183has_text_reloc: bool = false,178has_text_reloc: bool = false,
184num_ifunc_dynrelocs: usize = 0,179num_ifunc_dynrelocs: usize = 0,
...@@ -192,10 +187,6 @@ merge_sections: std.ArrayListUnmanaged(MergeSection) = .{},...@@ -192,10 +187,6 @@ merge_sections: std.ArrayListUnmanaged(MergeSection) = .{},
192/// Table of last atom index in a section and matching atom free list if any.187/// Table of last atom index in a section and matching atom free list if any.
193last_atom_and_free_list_table: LastAtomAndFreeListTable = .{},188last_atom_and_free_list_table: LastAtomAndFreeListTable = .{},
194189
195/// Global string table used to provide quick access to global symbol resolvers
196/// such as `resolver`.
197strings: StringTable = .{},
198
199first_eflags: ?elf.Elf64_Word = null,190first_eflags: ?elf.Elf64_Word = null,
200191
201/// When allocating, the ideal_capacity is calculated by192/// When allocating, the ideal_capacity is calculated by
...@@ -341,10 +332,6 @@ pub fn createEmpty(...@@ -341,10 +332,6 @@ pub fn createEmpty(
341332
342 const gpa = comp.gpa;333 const gpa = comp.gpa;
343334
344 // Index 0 is always a null symbol.
345 try self.symbols.append(gpa, .{});
346 // Index 0 is always a null symbol.
347 try self.symbols_extra.append(gpa, 0);
348 // Append null file at index 0335 // Append null file at index 0
349 try self.files.append(gpa, .null);336 try self.files.append(gpa, .null);
350 // Append null byte to string tables337 // Append null byte to string tables
...@@ -460,9 +447,6 @@ pub fn deinit(self: *Elf) void {...@@ -460,9 +447,6 @@ pub fn deinit(self: *Elf) void {
460 self.shstrtab.deinit(gpa);447 self.shstrtab.deinit(gpa);
461 self.symtab.deinit(gpa);448 self.symtab.deinit(gpa);
462 self.strtab.deinit(gpa);449 self.strtab.deinit(gpa);
463 self.symbols.deinit(gpa);
464 self.symbols_extra.deinit(gpa);
465 self.symbols_free_list.deinit(gpa);
466 self.resolver.deinit(gpa);450 self.resolver.deinit(gpa);
467451
468 for (self.thunks.items) |*th| {452 for (self.thunks.items) |*th| {
...@@ -478,8 +462,6 @@ pub fn deinit(self: *Elf) void {...@@ -478,8 +462,6 @@ pub fn deinit(self: *Elf) void {
478 }462 }
479 self.last_atom_and_free_list_table.deinit(gpa);463 self.last_atom_and_free_list_table.deinit(gpa);
480464
481 self.strings.deinit(gpa);
482
483 self.got.deinit(gpa);465 self.got.deinit(gpa);
484 self.plt.deinit(gpa);466 self.plt.deinit(gpa);
485 self.plt_got.deinit(gpa);467 self.plt_got.deinit(gpa);
...@@ -1300,6 +1282,9 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod...@@ -1300,6 +1282,9 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
1300 try self.finalizeMergeSections();1282 try self.finalizeMergeSections();
1301 try self.initOutputSections();1283 try self.initOutputSections();
1302 try self.initMergeSections();1284 try self.initMergeSections();
1285 if (self.linkerDefinedPtr()) |obj| {
1286 try obj.initStartStopSymbols(self);
1287 }
1303 self.claimUnresolved();1288 self.claimUnresolved();
13041289
1305 // Scan and create missing synthetic entries such as GOT indirection.1290 // Scan and create missing synthetic entries such as GOT indirection.
...@@ -1922,20 +1907,17 @@ fn accessLibPath(...@@ -1922,20 +1907,17 @@ fn accessLibPath(
1922/// 6. Re-run symbol resolution on pruned objects and shared objects sets.1907/// 6. Re-run symbol resolution on pruned objects and shared objects sets.
1923pub fn resolveSymbols(self: *Elf) !void {1908pub fn resolveSymbols(self: *Elf) !void {
1924 // Resolve symbols in the ZigObject. For now, we assume that it's always live.1909 // Resolve symbols in the ZigObject. For now, we assume that it's always live.
1925 if (self.zigObjectPtr()) |zig_object| zig_object.asFile().resolveSymbols(self);1910 if (self.zigObjectPtr()) |zo| try zo.asFile().resolveSymbols(self);
1926 // Resolve symbols on the set of all objects and shared objects (even if some are unneeded).1911 // Resolve symbols on the set of all objects and shared objects (even if some are unneeded).
1927 for (self.objects.items) |index| self.file(index).?.resolveSymbols(self);1912 for (self.objects.items) |index| try self.file(index).?.resolveSymbols(self);
1928 for (self.shared_objects.items) |index| self.file(index).?.resolveSymbols(self);1913 for (self.shared_objects.items) |index| try self.file(index).?.resolveSymbols(self);
1929 if (self.linkerDefinedPtr()) |obj| obj.asFile().resolveSymbols(self);1914 if (self.linkerDefinedPtr()) |obj| try obj.asFile().resolveSymbols(self);
19301915
1931 // Mark live objects.1916 // Mark live objects.
1932 self.markLive();1917 self.markLive();
19331918
1934 // Reset state of all globals after marking live objects.1919 // Reset state of all globals after marking live objects.
1935 if (self.zigObjectPtr()) |zig_object| zig_object.asFile().resetGlobals(self);1920 self.resolver.reset();
1936 for (self.objects.items) |index| self.file(index).?.resetGlobals(self);
1937 for (self.shared_objects.items) |index| self.file(index).?.resetGlobals(self);
1938 if (self.linkerDefinedPtr()) |obj| obj.asFile().resetGlobals(self);
19391921
1940 // Prune dead objects and shared objects.1922 // Prune dead objects and shared objects.
1941 var i: usize = 0;1923 var i: usize = 0;
...@@ -1968,10 +1950,10 @@ pub fn resolveSymbols(self: *Elf) !void {...@@ -1968,10 +1950,10 @@ pub fn resolveSymbols(self: *Elf) !void {
1968 }1950 }
19691951
1970 // Re-resolve the symbols.1952 // Re-resolve the symbols.
1971 if (self.zigObjectPtr()) |zig_object| zig_object.asFile().resolveSymbols(self);1953 if (self.zigObjectPtr()) |zo| try zo.asFile().resolveSymbols(self);
1972 for (self.objects.items) |index| self.file(index).?.resolveSymbols(self);1954 for (self.objects.items) |index| try self.file(index).?.resolveSymbols(self);
1973 for (self.shared_objects.items) |index| self.file(index).?.resolveSymbols(self);1955 for (self.shared_objects.items) |index| try self.file(index).?.resolveSymbols(self);
1974 if (self.linkerDefinedPtr()) |obj| obj.asFile().resolveSymbols(self);1956 if (self.linkerDefinedPtr()) |obj| try obj.asFile().resolveSymbols(self);
1975}1957}
19761958
1977/// Traverses all objects and shared objects marking any object referenced by1959/// Traverses all objects and shared objects marking any object referenced by
...@@ -2005,46 +1987,17 @@ fn convertCommonSymbols(self: *Elf) !void {...@@ -2005,46 +1987,17 @@ fn convertCommonSymbols(self: *Elf) !void {
2005}1987}
20061988
2007fn markImportsExports(self: *Elf) void {1989fn markImportsExports(self: *Elf) void {
2008 const mark = struct {1990 if (self.zigObjectPtr()) |zo| {
2009 fn mark(elf_file: *Elf, file_index: File.Index) void {1991 zo.markImportsExports(self);
2010 for (elf_file.file(file_index).?.globals()) |global_index| {1992 }
2011 const global = elf_file.symbol(global_index);1993 for (self.objects.items) |index| {
2012 if (global.version_index == elf.VER_NDX_LOCAL) continue;1994 self.file(index).?.object.markImportsExports(self);
2013 const file_ptr = global.file(elf_file) orelse continue;1995 }
2014 const vis = @as(elf.STV, @enumFromInt(global.elfSym(elf_file).st_other));
2015 if (vis == .HIDDEN) continue;
2016 if (file_ptr == .shared_object and !global.isAbs(elf_file)) {
2017 global.flags.import = true;
2018 continue;
2019 }
2020 if (file_ptr.index() == file_index) {
2021 global.flags.@"export" = true;
2022 if (elf_file.isEffectivelyDynLib() and vis != .PROTECTED) {
2023 global.flags.import = true;
2024 }
2025 }
2026 }
2027 }
2028 }.mark;
2029
2030 if (!self.isEffectivelyDynLib()) {1996 if (!self.isEffectivelyDynLib()) {
2031 for (self.shared_objects.items) |index| {1997 for (self.shared_objects.items) |index| {
2032 for (self.file(index).?.globals()) |global_index| {1998 self.file(index).?.shared_object.markImportExports(self);
2033 const global = self.symbol(global_index);
2034 const file_ptr = global.file(self) orelse continue;
2035 const vis = @as(elf.STV, @enumFromInt(global.elfSym(self).st_other));
2036 if (file_ptr != .shared_object and vis != .HIDDEN) global.flags.@"export" = true;
2037 }
2038 }1999 }
2039 }2000 }
2040
2041 if (self.zig_object_index) |index| {
2042 mark(self, index);
2043 }
2044
2045 for (self.objects.items) |index| {
2046 mark(self, index);
2047 }
2048}2001}
20492002
2050fn claimUnresolved(self: *Elf) void {2003fn claimUnresolved(self: *Elf) void {
...@@ -2063,22 +2016,27 @@ fn claimUnresolved(self: *Elf) void {...@@ -2063,22 +2016,27 @@ fn claimUnresolved(self: *Elf) void {
2063fn scanRelocs(self: *Elf) !void {2016fn scanRelocs(self: *Elf) !void {
2064 const gpa = self.base.comp.gpa;2017 const gpa = self.base.comp.gpa;
20652018
2066 var undefs = std.AutoHashMap(Symbol.Index, std.ArrayList(Ref)).init(gpa);2019 var undefs = std.AutoArrayHashMap(SymbolResolver.Index, std.ArrayList(Ref)).init(gpa);
2067 defer {2020 defer {
2068 var it = undefs.iterator();2021 for (undefs.values()) |*refs| {
2069 while (it.next()) |entry| {2022 refs.deinit();
2070 entry.value_ptr.deinit();
2071 }2023 }
2072 undefs.deinit();2024 undefs.deinit();
2073 }2025 }
20742026
2075 var objects = try std.ArrayList(File.Index).initCapacity(gpa, self.objects.items.len + 1);
2076 defer objects.deinit();
2077 if (self.zigObjectPtr()) |zo| objects.appendAssumeCapacity(zo.index);
2078 objects.appendSliceAssumeCapacity(self.objects.items);
2079
2080 var has_reloc_errors = false;2027 var has_reloc_errors = false;
2081 for (objects.items) |index| {2028 if (self.zigObjectPtr()) |zo| {
2029 zo.asFile().scanRelocs(self, &undefs) catch |err| switch (err) {
2030 error.RelaxFailure => unreachable,
2031 error.UnsupportedCpuArch => {
2032 try self.reportUnsupportedCpuArch();
2033 return error.FlushFailure;
2034 },
2035 error.RelocFailure => has_reloc_errors = true,
2036 else => |e| return e,
2037 };
2038 }
2039 for (self.objects.items) |index| {
2082 self.file(index).?.scanRelocs(self, &undefs) catch |err| switch (err) {2040 self.file(index).?.scanRelocs(self, &undefs) catch |err| switch (err) {
2083 error.RelaxFailure => unreachable,2041 error.RelaxFailure => unreachable,
2084 error.UnsupportedCpuArch => {2042 error.UnsupportedCpuArch => {
...@@ -2094,47 +2052,18 @@ fn scanRelocs(self: *Elf) !void {...@@ -2094,47 +2052,18 @@ fn scanRelocs(self: *Elf) !void {
20942052
2095 if (has_reloc_errors) return error.FlushFailure;2053 if (has_reloc_errors) return error.FlushFailure;
20962054
2097 for (self.symbols.items, 0..) |*sym, i| {2055 if (self.zigObjectPtr()) |zo| {
2098 const index = @as(u32, @intCast(i));2056 try zo.asFile().createSymbolIndirection(self);
2099 if (!sym.isLocal(self) and !sym.flags.has_dynamic) {2057 }
2100 log.debug("'{s}' is non-local", .{sym.name(self)});2058 for (self.objects.items) |index| {
2101 try self.dynsym.addSymbol(index, self);2059 try self.file(index).?.createSymbolIndirection(self);
2102 }2060 }
2103 if (sym.flags.needs_got) {2061 for (self.shared_objects.items) |index| {
2104 log.debug("'{s}' needs GOT", .{sym.name(self)});2062 try self.file(index).?.createSymbolIndirection(self);
2105 _ = try self.got.addGotSymbol(index, self);2063 }
2106 }2064 if (self.linkerDefinedPtr()) |obj| {
2107 if (sym.flags.needs_plt) {2065 try obj.asFile().createSymbolIndirection(self);
2108 if (sym.flags.is_canonical) {
2109 log.debug("'{s}' needs CPLT", .{sym.name(self)});
2110 sym.flags.@"export" = true;
2111 try self.plt.addSymbol(index, self);
2112 } else if (sym.flags.needs_got) {
2113 log.debug("'{s}' needs PLTGOT", .{sym.name(self)});
2114 try self.plt_got.addSymbol(index, self);
2115 } else {
2116 log.debug("'{s}' needs PLT", .{sym.name(self)});
2117 try self.plt.addSymbol(index, self);
2118 }
2119 }
2120 if (sym.flags.needs_copy_rel and !sym.flags.has_copy_rel) {
2121 log.debug("'{s}' needs COPYREL", .{sym.name(self)});
2122 try self.copy_rel.addSymbol(index, self);
2123 }
2124 if (sym.flags.needs_tlsgd) {
2125 log.debug("'{s}' needs TLSGD", .{sym.name(self)});
2126 try self.got.addTlsGdSymbol(index, self);
2127 }
2128 if (sym.flags.needs_gottp) {
2129 log.debug("'{s}' needs GOTTP", .{sym.name(self)});
2130 try self.got.addGotTpSymbol(index, self);
2131 }
2132 if (sym.flags.needs_tlsdesc) {
2133 log.debug("'{s}' needs TLSDESC", .{sym.name(self)});
2134 try self.got.addTlsDescSymbol(index, self);
2135 }
2136 }2066 }
2137
2138 if (self.got.flags.needs_tlsld) {2067 if (self.got.flags.needs_tlsld) {
2139 log.debug("program needs TLSLD", .{});2068 log.debug("program needs TLSLD", .{});
2140 try self.got.addTlsLdSymbol(self);2069 try self.got.addTlsLdSymbol(self);
...@@ -2911,8 +2840,8 @@ pub fn writeElfHeader(self: *Elf) !void {...@@ -2911,8 +2840,8 @@ pub fn writeElfHeader(self: *Elf) !void {
2911 index += 4;2840 index += 4;
29122841
2913 const e_entry: u64 = if (self.linkerDefinedPtr()) |obj| blk: {2842 const e_entry: u64 = if (self.linkerDefinedPtr()) |obj| blk: {
2914 const entry_index = obj.entry_index orelse break :blk 0;2843 const entry_sym = obj.entrySymbol(self) orelse break :blk 0;
2915 break :blk @intCast(self.symbol(entry_index).address(.{}, self));2844 break :blk @intCast(entry_sym.address(.{}, self));
2916 } else 0;2845 } else 0;
2917 const phdr_table_offset = if (self.phdr_table_index) |phndx| self.phdrs.items[phndx].p_offset else 0;2846 const phdr_table_offset = if (self.phdr_table_index) |phndx| self.phdrs.items[phndx].p_offset else 0;
2918 switch (self.ptr_width) {2847 switch (self.ptr_width) {
...@@ -3043,7 +2972,7 @@ pub fn deleteExport(...@@ -3043,7 +2972,7 @@ pub fn deleteExport(
3043fn checkDuplicates(self: *Elf) !void {2972fn checkDuplicates(self: *Elf) !void {
3044 const gpa = self.base.comp.gpa;2973 const gpa = self.base.comp.gpa;
30452974
3046 var dupes = std.AutoArrayHashMap(Symbol.Index, std.ArrayListUnmanaged(File.Index)).init(gpa);2975 var dupes = std.AutoArrayHashMap(SymbolResolver.Index, std.ArrayListUnmanaged(File.Index)).init(gpa);
3047 defer {2976 defer {
3048 for (dupes.values()) |*list| {2977 for (dupes.values()) |*list| {
3049 list.deinit(gpa);2978 list.deinit(gpa);
...@@ -3351,7 +3280,7 @@ fn initSyntheticSections(self: *Elf) !void {...@@ -3351,7 +3280,7 @@ fn initSyntheticSections(self: *Elf) !void {
3351 });3280 });
33523281
3353 const needs_versions = for (self.dynsym.entries.items) |entry| {3282 const needs_versions = for (self.dynsym.entries.items) |entry| {
3354 const sym = self.symbol(entry.symbol_index);3283 const sym = self.symbol(entry.ref).?;
3355 if (sym.flags.import and sym.version_index & elf.VERSYM_VERSION > elf.VER_NDX_GLOBAL) break true;3284 if (sym.flags.import and sym.version_index & elf.VERSYM_VERSION > elf.VER_NDX_GLOBAL) break true;
3356 } else false;3285 } else false;
3357 if (needs_versions) {3286 if (needs_versions) {
...@@ -3565,7 +3494,7 @@ fn setVersionSymtab(self: *Elf) !void {...@@ -3565,7 +3494,7 @@ fn setVersionSymtab(self: *Elf) !void {
3565 try self.versym.resize(gpa, self.dynsym.count());3494 try self.versym.resize(gpa, self.dynsym.count());
3566 self.versym.items[0] = elf.VER_NDX_LOCAL;3495 self.versym.items[0] = elf.VER_NDX_LOCAL;
3567 for (self.dynsym.entries.items, 1..) |entry, i| {3496 for (self.dynsym.entries.items, 1..) |entry, i| {
3568 const sym = self.symbol(entry.symbol_index);3497 const sym = self.symbol(entry.ref).?;
3569 self.versym.items[i] = sym.version_index;3498 self.versym.items[i] = sym.version_index;
3570 }3499 }
35713500
...@@ -4357,11 +4286,10 @@ fn allocateSpecialPhdrs(self: *Elf) void {...@@ -4357,11 +4286,10 @@ fn allocateSpecialPhdrs(self: *Elf) void {
4357fn writeAtoms(self: *Elf) !void {4286fn writeAtoms(self: *Elf) !void {
4358 const gpa = self.base.comp.gpa;4287 const gpa = self.base.comp.gpa;
43594288
4360 var undefs = std.AutoHashMap(Symbol.Index, std.ArrayList(Ref)).init(gpa);4289 var undefs = std.AutoArrayHashMap(SymbolResolver.Index, std.ArrayList(Ref)).init(gpa);
4361 defer {4290 defer {
4362 var it = undefs.iterator();4291 for (undefs.values()) |*refs| {
4363 while (it.next()) |entry| {4292 refs.deinit();
4364 entry.value_ptr.deinit();
4365 }4293 }
4366 undefs.deinit();4294 undefs.deinit();
4367 }4295 }
...@@ -4507,11 +4435,13 @@ pub fn updateSymtabSize(self: *Elf) !void {...@@ -4507,11 +4435,13 @@ pub fn updateSymtabSize(self: *Elf) !void {
4507 strsize += ctx.strsize;4435 strsize += ctx.strsize;
4508 }4436 }
45094437
4510 if (self.zig_got_section_index) |_| {4438 if (self.zigObjectPtr()) |_| {
4511 self.zig_got.output_symtab_ctx.ilocal = nlocals + 1;4439 if (self.zig_got_section_index) |_| {
4512 self.zig_got.updateSymtabSize(self);4440 self.zig_got.output_symtab_ctx.ilocal = nlocals + 1;
4513 nlocals += self.zig_got.output_symtab_ctx.nlocals;4441 self.zig_got.updateSymtabSize(self);
4514 strsize += self.zig_got.output_symtab_ctx.strsize;4442 nlocals += self.zig_got.output_symtab_ctx.nlocals;
4443 strsize += self.zig_got.output_symtab_ctx.strsize;
4444 }
4515 }4445 }
45164446
4517 if (self.got_section_index) |_| {4447 if (self.got_section_index) |_| {
...@@ -4650,7 +4580,9 @@ fn writeSyntheticSections(self: *Elf) !void {...@@ -4650,7 +4580,9 @@ fn writeSyntheticSections(self: *Elf) !void {
4650 const shdr = self.shdrs.items[shndx];4580 const shdr = self.shdrs.items[shndx];
4651 try self.got.addRela(self);4581 try self.got.addRela(self);
4652 try self.copy_rel.addRela(self);4582 try self.copy_rel.addRela(self);
4653 try self.zig_got.addRela(self);4583 if (self.zigObjectPtr()) |_| {
4584 try self.zig_got.addRela(self);
4585 }
4654 self.sortRelaDyn();4586 self.sortRelaDyn();
4655 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.rela_dyn.items), shdr.sh_offset);4587 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.rela_dyn.items), shdr.sh_offset);
4656 }4588 }
...@@ -5311,13 +5243,21 @@ pub fn calcNumIRelativeRelocs(self: *Elf) usize {...@@ -5311,13 +5243,21 @@ pub fn calcNumIRelativeRelocs(self: *Elf) usize {
53115243
5312 for (self.got.entries.items) |entry| {5244 for (self.got.entries.items) |entry| {
5313 if (entry.tag != .got) continue;5245 if (entry.tag != .got) continue;
5314 const sym = self.symbol(entry.symbol_index);5246 const sym = self.symbol(entry.ref).?;
5315 if (sym.isIFunc(self)) count += 1;5247 if (sym.isIFunc(self)) count += 1;
5316 }5248 }
53175249
5318 return count;5250 return count;
5319}5251}
53205252
5253pub fn getStartStopBasename(self: Elf, shdr: elf.Elf64_Shdr) ?[]const u8 {
5254 const name = self.getShString(shdr.sh_name);
5255 if (shdr.sh_flags & elf.SHF_ALLOC != 0 and name.len > 0) {
5256 if (Elf.isCIdentifier(name)) return name;
5257 }
5258 return null;
5259}
5260
5321pub fn isCIdentifier(name: []const u8) bool {5261pub fn isCIdentifier(name: []const u8) bool {
5322 if (name.len == 0) return false;5262 if (name.len == 0) return false;
5323 const first_c = name[0];5263 const first_c = name[0];
...@@ -5328,14 +5268,6 @@ pub fn isCIdentifier(name: []const u8) bool {...@@ -5328,14 +5268,6 @@ pub fn isCIdentifier(name: []const u8) bool {
5328 return true;5268 return true;
5329}5269}
53305270
5331pub fn getStartStopBasename(self: *Elf, shdr: elf.Elf64_Shdr) ?[]const u8 {
5332 const name = self.getShString(shdr.sh_name);
5333 if (shdr.sh_flags & elf.SHF_ALLOC != 0 and name.len > 0) {
5334 if (isCIdentifier(name)) return name;
5335 }
5336 return null;
5337}
5338
5339pub fn addThunk(self: *Elf) !Thunk.Index {5271pub fn addThunk(self: *Elf) !Thunk.Index {
5340 const index = @as(Thunk.Index, @intCast(self.thunks.items.len));5272 const index = @as(Thunk.Index, @intCast(self.thunks.items.len));
5341 const th = try self.thunks.addOne(self.base.comp.gpa);5273 const th = try self.thunks.addOne(self.base.comp.gpa);
...@@ -5381,95 +5313,9 @@ pub fn comdatGroup(self: *Elf, ref: Ref) *ComdatGroup {...@@ -5381,95 +5313,9 @@ pub fn comdatGroup(self: *Elf, ref: Ref) *ComdatGroup {
5381 return self.file(ref.file).?.comdatGroup(ref.index);5313 return self.file(ref.file).?.comdatGroup(ref.index);
5382}5314}
53835315
5384/// Returns pointer-to-symbol described at sym_index.5316pub fn symbol(self: *Elf, ref: Ref) ?*Symbol {
5385pub fn symbol(self: *Elf, sym_index: Symbol.Index) *Symbol {5317 const file_ptr = self.file(ref.file) orelse return null;
5386 return &self.symbols.items[sym_index];5318 return file_ptr.symbol(ref.index);
5387}
5388
5389pub fn addSymbol(self: *Elf) !Symbol.Index {
5390 const gpa = self.base.comp.gpa;
5391 try self.symbols.ensureUnusedCapacity(gpa, 1);
5392 const index = blk: {
5393 if (self.symbols_free_list.popOrNull()) |index| {
5394 log.debug(" (reusing symbol index {d})", .{index});
5395 break :blk index;
5396 } else {
5397 log.debug(" (allocating symbol index {d})", .{self.symbols.items.len});
5398 const index: Symbol.Index = @intCast(self.symbols.items.len);
5399 _ = self.symbols.addOneAssumeCapacity();
5400 break :blk index;
5401 }
5402 };
5403 self.symbols.items[index] = .{};
5404 return index;
5405}
5406
5407pub fn addSymbolExtra(self: *Elf, extra: Symbol.Extra) !u32 {
5408 const gpa = self.base.comp.gpa;
5409 const fields = @typeInfo(Symbol.Extra).Struct.fields;
5410 try self.symbols_extra.ensureUnusedCapacity(gpa, fields.len);
5411 return self.addSymbolExtraAssumeCapacity(extra);
5412}
5413
5414pub fn addSymbolExtraAssumeCapacity(self: *Elf, extra: Symbol.Extra) u32 {
5415 const index = @as(u32, @intCast(self.symbols_extra.items.len));
5416 const fields = @typeInfo(Symbol.Extra).Struct.fields;
5417 inline for (fields) |field| {
5418 self.symbols_extra.appendAssumeCapacity(switch (field.type) {
5419 u32 => @field(extra, field.name),
5420 else => @compileError("bad field type"),
5421 });
5422 }
5423 return index;
5424}
5425
5426pub fn symbolExtra(self: *Elf, index: u32) ?Symbol.Extra {
5427 if (index == 0) return null;
5428 const fields = @typeInfo(Symbol.Extra).Struct.fields;
5429 var i: usize = index;
5430 var result: Symbol.Extra = undefined;
5431 inline for (fields) |field| {
5432 @field(result, field.name) = switch (field.type) {
5433 u32 => self.symbols_extra.items[i],
5434 else => @compileError("bad field type"),
5435 };
5436 i += 1;
5437 }
5438 return result;
5439}
5440
5441pub fn setSymbolExtra(self: *Elf, index: u32, extra: Symbol.Extra) void {
5442 assert(index > 0);
5443 const fields = @typeInfo(Symbol.Extra).Struct.fields;
5444 inline for (fields, 0..) |field, i| {
5445 self.symbols_extra.items[index + i] = switch (field.type) {
5446 u32 => @field(extra, field.name),
5447 else => @compileError("bad field type"),
5448 };
5449 }
5450}
5451
5452const GetOrPutGlobalResult = struct {
5453 found_existing: bool,
5454 index: Symbol.Index,
5455};
5456
5457pub fn getOrPutGlobal(self: *Elf, name: []const u8) !GetOrPutGlobalResult {
5458 const gpa = self.base.comp.gpa;
5459 const name_off = try self.strings.insert(gpa, name);
5460 const gop = try self.resolver.getOrPut(gpa, name_off);
5461 if (!gop.found_existing) {
5462 const index = try self.addSymbol();
5463 log.debug("added symbol '{s}' at index {d}", .{ name, index });
5464 const global = self.symbol(index);
5465 global.name_offset = name_off;
5466 global.flags.global = true;
5467 gop.value_ptr.* = index;
5468 }
5469 return .{
5470 .found_existing = gop.found_existing,
5471 .index = gop.value_ptr.*,
5472 };
5473}5319}
54745320
5475pub fn getGlobalSymbol(self: *Elf, name: []const u8, lib_name: ?[]const u8) !u32 {5321pub fn getGlobalSymbol(self: *Elf, name: []const u8, lib_name: ?[]const u8) !u32 {
...@@ -5579,36 +5425,34 @@ fn reportUndefinedSymbols(self: *Elf, undefs: anytype) !void {...@@ -5579,36 +5425,34 @@ fn reportUndefinedSymbols(self: *Elf, undefs: anytype) !void {
55795425
5580 try self.base.comp.link_errors.ensureUnusedCapacity(gpa, undefs.count());5426 try self.base.comp.link_errors.ensureUnusedCapacity(gpa, undefs.count());
55815427
5582 var it = undefs.iterator();5428 for (undefs.keys(), undefs.values()) |key, refs| {
5583 while (it.next()) |entry| {5429 const undef_sym = self.resolver.keys.items[key - 1];
5584 const undef_index = entry.key_ptr.*;5430 const nrefs = @min(refs.items.len, max_notes);
5585 const atoms = entry.value_ptr.*.items;5431 const nnotes = nrefs + @intFromBool(refs.items.len > max_notes);
5586 const natoms = @min(atoms.len, max_notes);
5587 const nnotes = natoms + @intFromBool(atoms.len > max_notes);
55885432
5589 var err = try self.base.addErrorWithNotesAssumeCapacity(nnotes);5433 var err = try self.base.addErrorWithNotesAssumeCapacity(nnotes);
5590 try err.addMsg("undefined symbol: {s}", .{self.symbol(undef_index).name(self)});5434 try err.addMsg("undefined symbol: {s}", .{undef_sym.name(self)});
55915435
5592 for (atoms[0..natoms]) |ref| {5436 for (refs.items[0..nrefs]) |ref| {
5593 const atom_ptr = self.atom(ref).?;5437 const atom_ptr = self.atom(ref).?;
5594 const file_ptr = self.file(ref.file).?;5438 const file_ptr = atom_ptr.file(self).?;
5595 try err.addNote("referenced by {s}:{s}", .{ file_ptr.fmtPath(), atom_ptr.name(self) });5439 try err.addNote("referenced by {s}:{s}", .{ file_ptr.fmtPath(), atom_ptr.name(self) });
5596 }5440 }
55975441
5598 if (atoms.len > max_notes) {5442 if (refs.items.len > max_notes) {
5599 const remaining = atoms.len - max_notes;5443 const remaining = refs.items.len - max_notes;
5600 try err.addNote("referenced {d} more times", .{remaining});5444 try err.addNote("referenced {d} more times", .{remaining});
5601 }5445 }
5602 }5446 }
5603}5447}
56045448
5605fn reportDuplicates(self: *Elf, dupes: anytype) error{ HasDuplicates, OutOfMemory }!void {5449fn reportDuplicates(self: *Elf, dupes: anytype) error{ HasDuplicates, OutOfMemory }!void {
5450 if (dupes.keys().len == 0) return; // Nothing to do
5451
5606 const max_notes = 3;5452 const max_notes = 3;
5607 var has_dupes = false;5453
5608 var it = dupes.iterator();5454 for (dupes.keys(), dupes.values()) |key, notes| {
5609 while (it.next()) |entry| {5455 const sym = self.resolver.keys.items[key - 1];
5610 const sym = self.symbol(entry.key_ptr.*);
5611 const notes = entry.value_ptr.*;
5612 const nnotes = @min(notes.items.len, max_notes) + @intFromBool(notes.items.len > max_notes);5456 const nnotes = @min(notes.items.len, max_notes) + @intFromBool(notes.items.len > max_notes);
56135457
5614 var err = try self.base.addErrorWithNotes(nnotes + 1);5458 var err = try self.base.addErrorWithNotes(nnotes + 1);
...@@ -5625,11 +5469,9 @@ fn reportDuplicates(self: *Elf, dupes: anytype) error{ HasDuplicates, OutOfMemor...@@ -5625,11 +5469,9 @@ fn reportDuplicates(self: *Elf, dupes: anytype) error{ HasDuplicates, OutOfMemor
5625 const remaining = notes.items.len - max_notes;5469 const remaining = notes.items.len - max_notes;
5626 try err.addNote("defined {d} more times", .{remaining});5470 try err.addNote("defined {d} more times", .{remaining});
5627 }5471 }
5628
5629 has_dupes = true;
5630 }5472 }
56315473
5632 if (has_dupes) return error.HasDuplicates;5474 return error.HasDuplicates;
5633}5475}
56345476
5635fn reportMissingLibraryError(5477fn reportMissingLibraryError(
...@@ -6018,6 +5860,10 @@ pub const Ref = struct {...@@ -6018,6 +5860,10 @@ pub const Ref = struct {
6018 index: u32,5860 index: u32,
6019 file: u32,5861 file: u32,
60205862
5863 pub fn eql(ref: Ref, other: Ref) bool {
5864 return ref.index == other.index and ref.file == other.file;
5865 }
5866
6021 pub fn format(5867 pub fn format(
6022 ref: Ref,5868 ref: Ref,
6023 comptime unused_fmt_string: []const u8,5869 comptime unused_fmt_string: []const u8,
...@@ -6030,6 +5876,96 @@ pub const Ref = struct {...@@ -6030,6 +5876,96 @@ pub const Ref = struct {
6030 }5876 }
6031};5877};
60325878
5879pub const SymbolResolver = struct {
5880 keys: std.ArrayListUnmanaged(Key) = .{},
5881 values: std.ArrayListUnmanaged(Ref) = .{},
5882 table: std.AutoArrayHashMapUnmanaged(void, void) = .{},
5883
5884 const Result = struct {
5885 found_existing: bool,
5886 index: Index,
5887 ref: *Ref,
5888 };
5889
5890 pub fn deinit(resolver: *SymbolResolver, allocator: Allocator) void {
5891 resolver.keys.deinit(allocator);
5892 resolver.values.deinit(allocator);
5893 resolver.table.deinit(allocator);
5894 }
5895
5896 pub fn getOrPut(
5897 resolver: *SymbolResolver,
5898 allocator: Allocator,
5899 ref: Ref,
5900 elf_file: *Elf,
5901 ) !Result {
5902 const adapter = Adapter{ .keys = resolver.keys.items, .elf_file = elf_file };
5903 const key = Key{ .index = ref.index, .file_index = ref.file };
5904 const gop = try resolver.table.getOrPutAdapted(allocator, key, adapter);
5905 if (!gop.found_existing) {
5906 try resolver.keys.append(allocator, key);
5907 _ = try resolver.values.addOne(allocator);
5908 }
5909 return .{
5910 .found_existing = gop.found_existing,
5911 .index = @intCast(gop.index + 1),
5912 .ref = &resolver.values.items[gop.index],
5913 };
5914 }
5915
5916 pub fn get(resolver: SymbolResolver, index: Index) ?Ref {
5917 if (index == 0) return null;
5918 return resolver.values.items[index - 1];
5919 }
5920
5921 pub fn reset(resolver: *SymbolResolver) void {
5922 resolver.keys.clearRetainingCapacity();
5923 resolver.values.clearRetainingCapacity();
5924 resolver.table.clearRetainingCapacity();
5925 }
5926
5927 const Key = struct {
5928 index: Symbol.Index,
5929 file_index: File.Index,
5930
5931 fn name(key: Key, elf_file: *Elf) [:0]const u8 {
5932 const ref = Ref{ .index = key.index, .file = key.file_index };
5933 return elf_file.symbol(ref).?.name(elf_file);
5934 }
5935
5936 fn file(key: Key, elf_file: *Elf) ?File {
5937 return elf_file.file(key.file_index);
5938 }
5939
5940 fn eql(key: Key, other: Key, elf_file: *Elf) bool {
5941 const key_name = key.name(elf_file);
5942 const other_name = other.name(elf_file);
5943 return mem.eql(u8, key_name, other_name);
5944 }
5945
5946 fn hash(key: Key, elf_file: *Elf) u32 {
5947 return @truncate(Hash.hash(0, key.name(elf_file)));
5948 }
5949 };
5950
5951 const Adapter = struct {
5952 keys: []const Key,
5953 elf_file: *Elf,
5954
5955 pub fn eql(ctx: @This(), key: Key, b_void: void, b_map_index: usize) bool {
5956 _ = b_void;
5957 const other = ctx.keys[b_map_index];
5958 return key.eql(other, ctx.elf_file);
5959 }
5960
5961 pub fn hash(ctx: @This(), key: Key) u32 {
5962 return key.hash(ctx.elf_file);
5963 }
5964 };
5965
5966 pub const Index = u32;
5967};
5968
6033const LastAtomAndFreeList = struct {5969const LastAtomAndFreeList = struct {
6034 /// Index of the last allocated atom in this section.5970 /// Index of the last allocated atom in this section.
6035 last_atom_index: Atom.Index = 0,5971 last_atom_index: Atom.Index = 0,
...@@ -6143,6 +6079,7 @@ const File = @import("Elf/file.zig").File;...@@ -6143,6 +6079,7 @@ const File = @import("Elf/file.zig").File;
6143const GnuHashSection = synthetic_sections.GnuHashSection;6079const GnuHashSection = synthetic_sections.GnuHashSection;
6144const GotSection = synthetic_sections.GotSection;6080const GotSection = synthetic_sections.GotSection;
6145const GotPltSection = synthetic_sections.GotPltSection;6081const GotPltSection = synthetic_sections.GotPltSection;
6082const Hash = std.hash.Wyhash;
6146const HashSection = synthetic_sections.HashSection;6083const HashSection = synthetic_sections.HashSection;
6147const InputMergeSection = merge_section.InputMergeSection;6084const InputMergeSection = merge_section.InputMergeSection;
6148const LdScript = @import("Elf/LdScript.zig");6085const LdScript = @import("Elf/LdScript.zig");
src/link/Elf/Atom.zig+51-64
...@@ -326,12 +326,8 @@ pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.El...@@ -326,12 +326,8 @@ pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.El
326 const cpu_arch = elf_file.getTarget().cpu.arch;326 const cpu_arch = elf_file.getTarget().cpu.arch;
327 const file_ptr = self.file(elf_file).?;327 const file_ptr = self.file(elf_file).?;
328 for (self.relocs(elf_file)) |rel| {328 for (self.relocs(elf_file)) |rel| {
329 const target_index = switch (file_ptr) {329 const target_ref = file_ptr.resolveSymbol(rel.r_sym(), elf_file);
330 .zig_object => |x| x.symbol(rel.r_sym()),330 const target = elf_file.symbol(target_ref).?;
331 .object => |x| x.symbols.items[rel.r_sym()],
332 else => unreachable,
333 };
334 const target = elf_file.symbol(target_index);
335 const r_type = rel.r_type();331 const r_type = rel.r_type();
336 const r_offset: u64 = @intCast(self.value + @as(i64, @intCast(rel.r_offset)));332 const r_offset: u64 = @intCast(self.value + @as(i64, @intCast(rel.r_offset)));
337 var r_addend = rel.r_addend;333 var r_addend = rel.r_addend;
...@@ -422,12 +418,21 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype...@@ -422,12 +418,21 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype
422 const r_kind = relocation.decode(rel.r_type(), cpu_arch);418 const r_kind = relocation.decode(rel.r_type(), cpu_arch);
423 if (r_kind == .none) continue;419 if (r_kind == .none) continue;
424420
425 const symbol_index = switch (file_ptr) {421 const symbol_ref = file_ptr.resolveSymbol(rel.r_sym(), elf_file);
426 .zig_object => |x| x.symbol(rel.r_sym()),422 const symbol = elf_file.symbol(symbol_ref) orelse {
427 .object => |x| x.symbols.items[rel.r_sym()],423 const sym_name = switch (file_ptr) {
428 else => unreachable,424 .zig_object => |x| x.symbol(rel.r_sym()).name(elf_file),
425 inline else => |x| x.symbols.items[rel.r_sym()].name(elf_file),
426 };
427 // Violation of One Definition Rule for COMDATs.
428 // TODO convert into an error
429 log.debug("{}: {s}: {s} refers to a discarded COMDAT section", .{
430 file_ptr.fmtPath(),
431 self.name(elf_file),
432 sym_name,
433 });
434 continue;
429 };435 };
430 const symbol = elf_file.symbol(symbol_index);
431436
432 const is_synthetic_symbol = switch (file_ptr) {437 const is_synthetic_symbol = switch (file_ptr) {
433 .zig_object => false, // TODO: implement this once we support merge sections in ZigObject438 .zig_object => false, // TODO: implement this once we support merge sections in ZigObject
...@@ -435,19 +440,8 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype...@@ -435,19 +440,8 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype
435 else => unreachable,440 else => unreachable,
436 };441 };
437442
438 // Check for violation of One Definition Rule for COMDATs.
439 if (symbol.file(elf_file) == null) {
440 // TODO convert into an error
441 log.debug("{}: {s}: {s} refers to a discarded COMDAT section", .{
442 file_ptr.fmtPath(),
443 self.name(elf_file),
444 symbol.name(elf_file),
445 });
446 continue;
447 }
448
449 // Report an undefined symbol.443 // Report an undefined symbol.
450 if (!is_synthetic_symbol and (try self.reportUndefined(elf_file, symbol, symbol_index, rel, undefs)))444 if (!is_synthetic_symbol and (try self.reportUndefined(elf_file, symbol, rel, undefs)))
451 continue;445 continue;
452446
453 if (symbol.isIFunc(elf_file)) {447 if (symbol.isIFunc(elf_file)) {
...@@ -694,16 +688,15 @@ fn reportUndefined(...@@ -694,16 +688,15 @@ fn reportUndefined(
694 self: Atom,688 self: Atom,
695 elf_file: *Elf,689 elf_file: *Elf,
696 sym: *const Symbol,690 sym: *const Symbol,
697 sym_index: Symbol.Index,
698 rel: elf.Elf64_Rela,691 rel: elf.Elf64_Rela,
699 undefs: anytype,692 undefs: anytype,
700) !bool {693) !bool {
701 const comp = elf_file.base.comp;694 const comp = elf_file.base.comp;
702 const gpa = comp.gpa;695 const gpa = comp.gpa;
703 const rel_esym = switch (self.file(elf_file).?) {696 const file_ptr = self.file(elf_file).?;
704 .zig_object => |x| x.elfSym(rel.r_sym()).*,697 const rel_esym = switch (file_ptr) {
705 .object => |x| x.symtab.items[rel.r_sym()],698 .zig_object => |x| x.symbol(rel.r_sym()).elfSym(elf_file),
706 else => unreachable,699 inline else => |x| x.symtab.items[rel.r_sym()],
707 };700 };
708 const esym = sym.elfSym(elf_file);701 const esym = sym.elfSym(elf_file);
709 if (rel_esym.st_shndx == elf.SHN_UNDEF and702 if (rel_esym.st_shndx == elf.SHN_UNDEF and
...@@ -712,7 +705,12 @@ fn reportUndefined(...@@ -712,7 +705,12 @@ fn reportUndefined(
712 !sym.flags.import and705 !sym.flags.import and
713 esym.st_shndx == elf.SHN_UNDEF)706 esym.st_shndx == elf.SHN_UNDEF)
714 {707 {
715 const gop = try undefs.getOrPut(sym_index);708 const idx = switch (file_ptr) {
709 .zig_object => |x| x.symbols_resolver.items[rel.r_sym() & ZigObject.symbol_mask],
710 .object => |x| x.symbols_resolver.items[rel.r_sym() - x.first_global.?],
711 inline else => |x| x.symbols_resolver.items[rel.r_sym()],
712 };
713 const gop = try undefs.getOrPut(idx);
716 if (!gop.found_existing) {714 if (!gop.found_existing) {
717 gop.value_ptr.* = std.ArrayList(Elf.Ref).init(gpa);715 gop.value_ptr.* = std.ArrayList(Elf.Ref).init(gpa);
718 }716 }
...@@ -737,11 +735,8 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi...@@ -737,11 +735,8 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi
737 const r_kind = relocation.decode(rel.r_type(), cpu_arch);735 const r_kind = relocation.decode(rel.r_type(), cpu_arch);
738 if (r_kind == .none) continue;736 if (r_kind == .none) continue;
739737
740 const target = switch (file_ptr) {738 const target_ref = file_ptr.resolveSymbol(rel.r_sym(), elf_file);
741 .zig_object => |x| elf_file.symbol(x.symbol(rel.r_sym())),739 const target = elf_file.symbol(target_ref).?;
742 .object => |x| elf_file.symbol(x.symbols.items[rel.r_sym()]),
743 else => unreachable,
744 };
745 const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;740 const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;
746741
747 // We will use equation format to resolve relocations:742 // We will use equation format to resolve relocations:
...@@ -845,7 +840,7 @@ fn resolveDynAbsReloc(...@@ -845,7 +840,7 @@ fn resolveDynAbsReloc(
845 if (is_writeable or elf_file.z_nocopyreloc) {840 if (is_writeable or elf_file.z_nocopyreloc) {
846 elf_file.addRelaDynAssumeCapacity(.{841 elf_file.addRelaDynAssumeCapacity(.{
847 .offset = P,842 .offset = P,
848 .sym = target.extra(elf_file).?.dynamic,843 .sym = target.extra(elf_file).dynamic,
849 .type = relocation.encode(.abs, cpu_arch),844 .type = relocation.encode(.abs, cpu_arch),
850 .addend = A,845 .addend = A,
851 });846 });
...@@ -859,7 +854,7 @@ fn resolveDynAbsReloc(...@@ -859,7 +854,7 @@ fn resolveDynAbsReloc(
859 if (is_writeable) {854 if (is_writeable) {
860 elf_file.addRelaDynAssumeCapacity(.{855 elf_file.addRelaDynAssumeCapacity(.{
861 .offset = P,856 .offset = P,
862 .sym = target.extra(elf_file).?.dynamic,857 .sym = target.extra(elf_file).dynamic,
863 .type = relocation.encode(.abs, cpu_arch),858 .type = relocation.encode(.abs, cpu_arch),
864 .addend = A,859 .addend = A,
865 });860 });
...@@ -872,7 +867,7 @@ fn resolveDynAbsReloc(...@@ -872,7 +867,7 @@ fn resolveDynAbsReloc(
872 .dynrel => {867 .dynrel => {
873 elf_file.addRelaDynAssumeCapacity(.{868 elf_file.addRelaDynAssumeCapacity(.{
874 .offset = P,869 .offset = P,
875 .sym = target.extra(elf_file).?.dynamic,870 .sym = target.extra(elf_file).dynamic,
876 .type = relocation.encode(.abs, cpu_arch),871 .type = relocation.encode(.abs, cpu_arch),
877 .addend = A,872 .addend = A,
878 });873 });
...@@ -923,31 +918,29 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any...@@ -923,31 +918,29 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any
923918
924 const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;919 const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;
925920
926 const target_index = switch (file_ptr) {921 const target_ref = file_ptr.resolveSymbol(rel.r_sym(), elf_file);
927 .zig_object => |x| x.symbol(rel.r_sym()),922 const target = elf_file.symbol(target_ref) orelse {
928 .object => |x| x.symbols.items[rel.r_sym()],923 const sym_name = switch (file_ptr) {
929 else => unreachable,924 .zig_object => |x| x.symbol(rel.r_sym()).name(elf_file),
930 };925 inline else => |x| x.symbols.items[rel.r_sym()].name(elf_file),
931 const target = elf_file.symbol(target_index);926 };
932 const is_synthetic_symbol = switch (file_ptr) {927 // Violation of One Definition Rule for COMDATs.
933 .zig_object => false, // TODO: implement this once we support merge sections in ZigObject
934 .object => |x| rel.r_sym() >= x.symtab.items.len,
935 else => unreachable,
936 };
937
938 // Check for violation of One Definition Rule for COMDATs.
939 if (target.file(elf_file) == null) {
940 // TODO convert into an error928 // TODO convert into an error
941 log.debug("{}: {s}: {s} refers to a discarded COMDAT section", .{929 log.debug("{}: {s}: {s} refers to a discarded COMDAT section", .{
942 file_ptr.fmtPath(),930 file_ptr.fmtPath(),
943 self.name(elf_file),931 self.name(elf_file),
944 target.name(elf_file),932 sym_name,
945 });933 });
946 continue;934 continue;
947 }935 };
936 const is_synthetic_symbol = switch (file_ptr) {
937 .zig_object => false, // TODO: implement this once we support merge sections in ZigObject
938 .object => |x| rel.r_sym() >= x.symtab.items.len,
939 else => unreachable,
940 };
948941
949 // Report an undefined symbol.942 // Report an undefined symbol.
950 if (!is_synthetic_symbol and (try self.reportUndefined(elf_file, target, target_index, rel, undefs)))943 if (!is_synthetic_symbol and (try self.reportUndefined(elf_file, target, rel, undefs)))
951 continue;944 continue;
952945
953 // We will use equation format to resolve relocations:946 // We will use equation format to resolve relocations:
...@@ -1766,11 +1759,7 @@ const aarch64 = struct {...@@ -1766,11 +1759,7 @@ const aarch64 = struct {
1766 => {1759 => {
1767 const disp: i28 = math.cast(i28, S + A - P) orelse blk: {1760 const disp: i28 = math.cast(i28, S + A - P) orelse blk: {
1768 const th = atom.thunk(elf_file);1761 const th = atom.thunk(elf_file);
1769 const target_index = switch (file_ptr) {1762 const target_index = file_ptr.resolveSymbol(rel.r_sym(), elf_file);
1770 .zig_object => |x| x.symbol(rel.r_sym()),
1771 .object => |x| x.symbols.items[rel.r_sym()],
1772 else => unreachable,
1773 };
1774 const S_ = th.targetAddress(target_index, elf_file);1763 const S_ = th.targetAddress(target_index, elf_file);
1775 break :blk math.cast(i28, S_ + A - P) orelse return error.Overflow;1764 break :blk math.cast(i28, S_ + A - P) orelse return error.Overflow;
1776 };1765 };
...@@ -2106,11 +2095,8 @@ const riscv = struct {...@@ -2106,11 +2095,8 @@ const riscv = struct {
2106 return error.RelocFailure;2095 return error.RelocFailure;
2107 };2096 };
2108 it.pos = pos;2097 it.pos = pos;
2109 const target_ = switch (file_ptr) {2098 const target_ref_ = file_ptr.resolveSymbol(pair.r_sym(), elf_file);
2110 .zig_object => |x| elf_file.symbol(x.symbol(pair.r_sym())),2099 const target_ = elf_file.symbol(target_ref_).?;
2111 .object => |x| elf_file.symbol(x.symbols.items[pair.r_sym()]),
2112 else => unreachable,
2113 };
2114 const S_ = target_.address(.{}, elf_file);2100 const S_ = target_.address(.{}, elf_file);
2115 const A_ = pair.r_addend;2101 const A_ = pair.r_addend;
2116 const P_ = atom_addr + @as(i64, @intCast(pair.r_offset));2102 const P_ = atom_addr + @as(i64, @intCast(pair.r_offset));
...@@ -2313,4 +2299,5 @@ const File = @import("file.zig").File;...@@ -2313,4 +2299,5 @@ const File = @import("file.zig").File;
2313const Object = @import("Object.zig");2299const Object = @import("Object.zig");
2314const Symbol = @import("Symbol.zig");2300const Symbol = @import("Symbol.zig");
2315const Thunk = @import("thunks.zig").Thunk;2301const Thunk = @import("thunks.zig").Thunk;
2302const ZigObject = @import("ZigObject.zig");
2316const dev = @import("../../dev.zig");2303const dev = @import("../../dev.zig");
src/link/Elf/LinkerDefined.zig+268-143
...@@ -2,7 +2,10 @@ index: File.Index,...@@ -2,7 +2,10 @@ index: File.Index,
22
3symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},3symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
4strtab: std.ArrayListUnmanaged(u8) = .{},4strtab: std.ArrayListUnmanaged(u8) = .{},
5symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},5
6symbols: std.ArrayListUnmanaged(Symbol) = .{},
7symbols_extra: std.ArrayListUnmanaged(u32) = .{},
8symbols_resolver: std.ArrayListUnmanaged(Elf.SymbolResolver.Index) = .{},
69
7entry_index: ?Symbol.Index = null,10entry_index: ?Symbol.Index = null,
8dynamic_index: ?Symbol.Index = null,11dynamic_index: ?Symbol.Index = null,
...@@ -29,6 +32,8 @@ pub fn deinit(self: *LinkerDefined, allocator: Allocator) void {...@@ -29,6 +32,8 @@ pub fn deinit(self: *LinkerDefined, allocator: Allocator) void {
29 self.symtab.deinit(allocator);32 self.symtab.deinit(allocator);
30 self.strtab.deinit(allocator);33 self.strtab.deinit(allocator);
31 self.symbols.deinit(allocator);34 self.symbols.deinit(allocator);
35 self.symbols_extra.deinit(allocator);
36 self.symbols_resolver.deinit(allocator);
32 self.start_stop_indexes.deinit(allocator);37 self.start_stop_indexes.deinit(allocator);
33}38}
3439
...@@ -37,86 +42,150 @@ pub fn init(self: *LinkerDefined, allocator: Allocator) !void {...@@ -37,86 +42,150 @@ pub fn init(self: *LinkerDefined, allocator: Allocator) !void {
37 try self.strtab.append(allocator, 0);42 try self.strtab.append(allocator, 0);
38}43}
3944
45fn newSymbolAssumeCapacity(self: *LinkerDefined, name_off: u32, elf_file: *Elf) Symbol.Index {
46 const esym_index: u32 = @intCast(self.symtab.items.len);
47 const esym = self.symtab.addOneAssumeCapacity();
48 esym.* = .{
49 .st_name = name_off,
50 .st_info = elf.STB_GLOBAL << 4,
51 .st_other = @intFromEnum(elf.STV.HIDDEN),
52 .st_shndx = elf.SHN_ABS,
53 .st_value = 0,
54 .st_size = 0,
55 };
56 const index = self.addSymbolAssumeCapacity();
57 const symbol = &self.symbols.items[index];
58 symbol.name_offset = name_off;
59 symbol.extra_index = self.addSymbolExtraAssumeCapacity(.{});
60 symbol.ref = .{ .index = 0, .file = 0 };
61 symbol.esym_index = esym_index;
62 symbol.version_index = elf_file.default_sym_version;
63 return index;
64}
65
40pub fn initSymbols(self: *LinkerDefined, elf_file: *Elf) !void {66pub fn initSymbols(self: *LinkerDefined, elf_file: *Elf) !void {
41 const gpa = elf_file.base.comp.gpa;67 const gpa = elf_file.base.comp.gpa;
4268
69 var nsyms: usize = 0;
70 if (elf_file.entry_name) |_| {
71 nsyms += 1; // entry
72 }
73 nsyms += 1; // _DYNAMIC
74 nsyms += 1; // __ehdr_start
75 nsyms += 1; // __init_array_start
76 nsyms += 1; // __init_array_end
77 nsyms += 1; // __fini_array_start
78 nsyms += 1; // __fini_array_end
79 nsyms += 1; // __preinit_array_start
80 nsyms += 1; // __preinit_array_end
81 nsyms += 1; // _GLOBAL_OFFSET_TABLE_
82 nsyms += 1; // _PROCEDURE_LINKAGE_TABLE_
83 nsyms += 1; // _end
84 if (elf_file.base.comp.link_eh_frame_hdr) {
85 nsyms += 1; // __GNU_EH_FRAME_HDR
86 }
87 nsyms += 1; // __dso_handle
88 nsyms += 1; // __rela_iplt_start
89 nsyms += 1; // __rela_iplt_end
90 if (elf_file.getTarget().cpu.arch.isRISCV() and elf_file.isEffectivelyDynLib()) {
91 nsyms += 1; // __global_pointer$
92 }
93
94 try self.symtab.ensureTotalCapacityPrecise(gpa, nsyms);
95 try self.symbols.ensureTotalCapacityPrecise(gpa, nsyms);
96 try self.symbols_extra.ensureTotalCapacityPrecise(gpa, nsyms * @sizeOf(Symbol.Extra));
97 try self.symbols_resolver.ensureTotalCapacityPrecise(gpa, nsyms);
98 self.symbols_resolver.resize(gpa, nsyms) catch unreachable;
99 @memset(self.symbols_resolver.items, 0);
100
43 if (elf_file.entry_name) |name| {101 if (elf_file.entry_name) |name| {
44 self.entry_index = try self.addGlobal(name, elf_file);102 self.entry_index = self.newSymbolAssumeCapacity(try self.addString(gpa, name), elf_file);
45 }103 }
46104
47 self.dynamic_index = try self.addGlobal("_DYNAMIC", elf_file);105 self.dynamic_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "_DYNAMIC"), elf_file);
48 self.ehdr_start_index = try self.addGlobal("__ehdr_start", elf_file);106 self.ehdr_start_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__ehdr_start"), elf_file);
49 self.init_array_start_index = try self.addGlobal("__init_array_start", elf_file);107 self.init_array_start_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__init_array_start"), elf_file);
50 self.init_array_end_index = try self.addGlobal("__init_array_end", elf_file);108 self.init_array_end_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__init_array_end"), elf_file);
51 self.fini_array_start_index = try self.addGlobal("__fini_array_start", elf_file);109 self.fini_array_start_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__fini_array_start"), elf_file);
52 self.fini_array_end_index = try self.addGlobal("__fini_array_end", elf_file);110 self.fini_array_end_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__fini_array_end"), elf_file);
53 self.preinit_array_start_index = try self.addGlobal("__preinit_array_start", elf_file);111 self.preinit_array_start_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__preinit_array_start"), elf_file);
54 self.preinit_array_end_index = try self.addGlobal("__preinit_array_end", elf_file);112 self.preinit_array_end_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__preinit_array_end"), elf_file);
55 self.got_index = try self.addGlobal("_GLOBAL_OFFSET_TABLE_", elf_file);113 self.got_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "_GLOBAL_OFFSET_TABLE_"), elf_file);
56 self.plt_index = try self.addGlobal("_PROCEDURE_LINKAGE_TABLE_", elf_file);114 self.plt_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "_PROCEDURE_LINKAGE_TABLE_"), elf_file);
57 self.end_index = try self.addGlobal("_end", elf_file);115 self.end_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "_end"), elf_file);
58116
59 if (elf_file.base.comp.link_eh_frame_hdr) {117 if (elf_file.base.comp.link_eh_frame_hdr) {
60 self.gnu_eh_frame_hdr_index = try self.addGlobal("__GNU_EH_FRAME_HDR", elf_file);118 self.gnu_eh_frame_hdr_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__GNU_EH_FRAME_HDR"), elf_file);
61 }119 }
62120
63 self.dso_handle_index = try self.addGlobal("__dso_handle", elf_file);121 self.dso_handle_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__dso_handle"), elf_file);
64 self.rela_iplt_start_index = try self.addGlobal("__rela_iplt_start", elf_file);122 self.rela_iplt_start_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__rela_iplt_start"), elf_file);
65 self.rela_iplt_end_index = try self.addGlobal("__rela_iplt_end", elf_file);123 self.rela_iplt_end_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__rela_iplt_end"), elf_file);
66124
67 for (elf_file.shdrs.items) |shdr| {125 if (elf_file.getTarget().cpu.arch.isRISCV() and elf_file.isEffectivelyDynLib()) {
68 if (elf_file.getStartStopBasename(shdr)) |name| {126 self.global_pointer_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__global_pointer$"), elf_file);
69 try self.start_stop_indexes.ensureUnusedCapacity(gpa, 2);127 }
128}
70129
71 const start = try std.fmt.allocPrintZ(gpa, "__start_{s}", .{name});130pub fn initStartStopSymbols(self: *LinkerDefined, elf_file: *Elf) !void {
72 defer gpa.free(start);131 const gpa = elf_file.base.comp.gpa;
73 const stop = try std.fmt.allocPrintZ(gpa, "__stop_{s}", .{name});
74 defer gpa.free(stop);
75132
76 self.start_stop_indexes.appendAssumeCapacity(try self.addGlobal(start, elf_file));133 var nsyms: usize = 0;
77 self.start_stop_indexes.appendAssumeCapacity(try self.addGlobal(stop, elf_file));134 for (elf_file.shdrs.items) |shdr| {
135 if (elf_file.getStartStopBasename(shdr)) |_| {
136 nsyms += 2; // __start_, __stop_
78 }137 }
79 }138 }
80139
81 if (elf_file.getTarget().cpu.arch.isRISCV() and elf_file.isEffectivelyDynLib()) {140 try self.start_stop_indexes.ensureTotalCapacityPrecise(gpa, nsyms);
82 self.global_pointer_index = try self.addGlobal("__global_pointer$", elf_file);141 try self.symtab.ensureUnusedCapacity(gpa, nsyms);
142 try self.symbols.ensureUnusedCapacity(gpa, nsyms);
143 try self.symbols_extra.ensureUnusedCapacity(gpa, nsyms * @sizeOf(Symbol.Extra));
144 try self.symbols_resolver.ensureUnusedCapacity(gpa, nsyms);
145
146 for (elf_file.shdrs.items) |shdr| {
147 if (elf_file.getStartStopBasename(shdr)) |name| {
148 const start_name = try std.fmt.allocPrintZ(gpa, "__start_{s}", .{name});
149 defer gpa.free(start_name);
150 const stop_name = try std.fmt.allocPrintZ(gpa, "__stop_{s}", .{name});
151 defer gpa.free(stop_name);
152
153 for (&[_][]const u8{ start_name, stop_name }) |nn| {
154 const index = self.newSymbolAssumeCapacity(try self.addString(gpa, nn), elf_file);
155 self.start_stop_indexes.appendAssumeCapacity(index);
156 const gop = try elf_file.resolver.getOrPut(gpa, .{
157 .index = index,
158 .file = self.index,
159 }, elf_file);
160 assert(!gop.found_existing);
161 gop.ref.* = .{ .index = index, .file = self.index };
162 self.symbols_resolver.appendAssumeCapacity(gop.index);
163 }
164 }
83 }165 }
84}166}
85167
86fn addGlobal(self: *LinkerDefined, name: []const u8, elf_file: *Elf) !u32 {168pub fn resolveSymbols(self: *LinkerDefined, elf_file: *Elf) !void {
87 const comp = elf_file.base.comp;169 const gpa = elf_file.base.comp.gpa;
88 const gpa = comp.gpa;
89 try self.symtab.ensureUnusedCapacity(gpa, 1);
90 try self.symbols.ensureUnusedCapacity(gpa, 1);
91 const name_off = @as(u32, @intCast(self.strtab.items.len));
92 try self.strtab.writer(gpa).print("{s}\x00", .{name});
93 self.symtab.appendAssumeCapacity(.{
94 .st_name = name_off,
95 .st_info = elf.STB_GLOBAL << 4,
96 .st_other = @intFromEnum(elf.STV.HIDDEN),
97 .st_shndx = elf.SHN_ABS,
98 .st_value = 0,
99 .st_size = 0,
100 });
101 const gop = try elf_file.getOrPutGlobal(name);
102 self.symbols.addOneAssumeCapacity().* = gop.index;
103 return gop.index;
104}
105170
106pub fn resolveSymbols(self: *LinkerDefined, elf_file: *Elf) void {171 for (self.symtab.items, self.symbols_resolver.items, 0..) |esym, *resolv, i| {
107 for (self.symbols.items, 0..) |index, i| {172 const gop = try elf_file.resolver.getOrPut(gpa, .{
108 const sym_idx = @as(Symbol.Index, @intCast(i));173 .index = @intCast(i),
109 const this_sym = self.symtab.items[sym_idx];174 .file = self.index,
175 }, elf_file);
176 if (!gop.found_existing) {
177 gop.ref.* = .{ .index = 0, .file = 0 };
178 }
179 resolv.* = gop.index;
110180
111 if (this_sym.st_shndx == elf.SHN_UNDEF) continue;181 if (esym.st_shndx == elf.SHN_UNDEF) continue;
182 if (elf_file.symbol(gop.ref.*) == null) {
183 gop.ref.* = .{ .index = @intCast(i), .file = self.index };
184 continue;
185 }
112186
113 const global = elf_file.symbol(index);187 if (self.asFile().symbolRank(esym, false) < elf_file.symbol(gop.ref.*).?.symbolRank(elf_file)) {
114 if (self.asFile().symbolRank(this_sym, false) < global.symbolRank(elf_file)) {188 gop.ref.* = .{ .index = @intCast(i), .file = self.index };
115 global.value = 0;
116 global.ref = .{ .index = 0, .file = 0 };
117 global.file_index = self.index;
118 global.esym_index = sym_idx;
119 global.version_index = elf_file.default_sym_version;
120 }189 }
121 }190 }
122}191}
...@@ -125,93 +194,73 @@ pub fn allocateSymbols(self: *LinkerDefined, elf_file: *Elf) void {...@@ -125,93 +194,73 @@ pub fn allocateSymbols(self: *LinkerDefined, elf_file: *Elf) void {
125 const comp = elf_file.base.comp;194 const comp = elf_file.base.comp;
126 const link_mode = comp.config.link_mode;195 const link_mode = comp.config.link_mode;
127196
197 const allocSymbol = struct {
198 fn allocSymbol(ld: *LinkerDefined, index: Symbol.Index, value: u64, osec: u32, ef: *Elf) void {
199 const sym = ef.symbol(ld.resolveSymbol(index, ef)).?;
200 sym.value = @intCast(value);
201 sym.output_section_index = osec;
202 }
203 }.allocSymbol;
204
128 // _DYNAMIC205 // _DYNAMIC
129 if (elf_file.dynamic_section_index) |shndx| {206 if (elf_file.dynamic_section_index) |shndx| {
130 const shdr = &elf_file.shdrs.items[shndx];207 const shdr = &elf_file.shdrs.items[shndx];
131 const symbol_ptr = elf_file.symbol(self.dynamic_index.?);208 allocSymbol(self, self.dynamic_index.?, shdr.sh_addr, shndx, elf_file);
132 symbol_ptr.value = @intCast(shdr.sh_addr);
133 symbol_ptr.output_section_index = shndx;
134 }209 }
135210
136 // __ehdr_start211 // __ehdr_start
137 {212 allocSymbol(self, self.ehdr_start_index.?, elf_file.image_base, 1, elf_file);
138 const symbol_ptr = elf_file.symbol(self.ehdr_start_index.?);
139 symbol_ptr.value = @intCast(elf_file.image_base);
140 symbol_ptr.output_section_index = 1;
141 }
142213
143 // __init_array_start, __init_array_end214 // __init_array_start, __init_array_end
144 if (elf_file.sectionByName(".init_array")) |shndx| {215 if (elf_file.sectionByName(".init_array")) |shndx| {
145 const start_sym = elf_file.symbol(self.init_array_start_index.?);
146 const end_sym = elf_file.symbol(self.init_array_end_index.?);
147 const shdr = &elf_file.shdrs.items[shndx];216 const shdr = &elf_file.shdrs.items[shndx];
148 start_sym.output_section_index = shndx;217 allocSymbol(self, self.init_array_start_index.?, shdr.sh_addr, shndx, elf_file);
149 start_sym.value = @intCast(shdr.sh_addr);218 allocSymbol(self, self.init_array_end_index.?, shdr.sh_addr + shdr.sh_size, shndx, elf_file);
150 end_sym.output_section_index = shndx;
151 end_sym.value = @intCast(shdr.sh_addr + shdr.sh_size);
152 }219 }
153220
154 // __fini_array_start, __fini_array_end221 // __fini_array_start, __fini_array_end
155 if (elf_file.sectionByName(".fini_array")) |shndx| {222 if (elf_file.sectionByName(".fini_array")) |shndx| {
156 const start_sym = elf_file.symbol(self.fini_array_start_index.?);
157 const end_sym = elf_file.symbol(self.fini_array_end_index.?);
158 const shdr = &elf_file.shdrs.items[shndx];223 const shdr = &elf_file.shdrs.items[shndx];
159 start_sym.output_section_index = shndx;224 allocSymbol(self, self.fini_array_start_index.?, shdr.sh_addr, shndx, elf_file);
160 start_sym.value = @intCast(shdr.sh_addr);225 allocSymbol(self, self.fini_array_end_index.?, shdr.sh_addr + shdr.sh_size, shndx, elf_file);
161 end_sym.output_section_index = shndx;
162 end_sym.value = @intCast(shdr.sh_addr + shdr.sh_size);
163 }226 }
164227
165 // __preinit_array_start, __preinit_array_end228 // __preinit_array_start, __preinit_array_end
166 if (elf_file.sectionByName(".preinit_array")) |shndx| {229 if (elf_file.sectionByName(".preinit_array")) |shndx| {
167 const start_sym = elf_file.symbol(self.preinit_array_start_index.?);
168 const end_sym = elf_file.symbol(self.preinit_array_end_index.?);
169 const shdr = &elf_file.shdrs.items[shndx];230 const shdr = &elf_file.shdrs.items[shndx];
170 start_sym.output_section_index = shndx;231 allocSymbol(self, self.preinit_array_start_index.?, shdr.sh_addr, shndx, elf_file);
171 start_sym.value = @intCast(shdr.sh_addr);232 allocSymbol(self, self.preinit_array_end_index.?, shdr.sh_addr + shdr.sh_size, shndx, elf_file);
172 end_sym.output_section_index = shndx;
173 end_sym.value = @intCast(shdr.sh_addr + shdr.sh_size);
174 }233 }
175234
176 // _GLOBAL_OFFSET_TABLE_235 // _GLOBAL_OFFSET_TABLE_
177 if (elf_file.getTarget().cpu.arch == .x86_64) {236 if (elf_file.getTarget().cpu.arch == .x86_64) {
178 if (elf_file.got_plt_section_index) |shndx| {237 if (elf_file.got_plt_section_index) |shndx| {
179 const shdr = elf_file.shdrs.items[shndx];238 const shdr = elf_file.shdrs.items[shndx];
180 const sym = elf_file.symbol(self.got_index.?);239 allocSymbol(self, self.got_index.?, shdr.sh_addr, shndx, elf_file);
181 sym.value = @intCast(shdr.sh_addr);
182 sym.output_section_index = shndx;
183 }240 }
184 } else {241 } else {
185 if (elf_file.got_section_index) |shndx| {242 if (elf_file.got_section_index) |shndx| {
186 const shdr = elf_file.shdrs.items[shndx];243 const shdr = elf_file.shdrs.items[shndx];
187 const sym = elf_file.symbol(self.got_index.?);244 allocSymbol(self, self.got_index.?, shdr.sh_addr, shndx, elf_file);
188 sym.value = @intCast(shdr.sh_addr);
189 sym.output_section_index = shndx;
190 }245 }
191 }246 }
192247
193 // _PROCEDURE_LINKAGE_TABLE_248 // _PROCEDURE_LINKAGE_TABLE_
194 if (elf_file.plt_section_index) |shndx| {249 if (elf_file.plt_section_index) |shndx| {
195 const shdr = &elf_file.shdrs.items[shndx];250 const shdr = &elf_file.shdrs.items[shndx];
196 const symbol_ptr = elf_file.symbol(self.plt_index.?);251 allocSymbol(self, self.plt_index.?, shdr.sh_addr, shndx, elf_file);
197 symbol_ptr.value = @intCast(shdr.sh_addr);
198 symbol_ptr.output_section_index = shndx;
199 }252 }
200253
201 // __dso_handle254 // __dso_handle
202 if (self.dso_handle_index) |index| {255 if (self.dso_handle_index) |index| {
203 const shdr = &elf_file.shdrs.items[1];256 const shdr = &elf_file.shdrs.items[1];
204 const symbol_ptr = elf_file.symbol(index);257 allocSymbol(self, index, shdr.sh_addr, 0, elf_file);
205 symbol_ptr.value = @intCast(shdr.sh_addr);
206 symbol_ptr.output_section_index = 0;
207 }258 }
208259
209 // __GNU_EH_FRAME_HDR260 // __GNU_EH_FRAME_HDR
210 if (elf_file.eh_frame_hdr_section_index) |shndx| {261 if (elf_file.eh_frame_hdr_section_index) |shndx| {
211 const shdr = &elf_file.shdrs.items[shndx];262 const shdr = &elf_file.shdrs.items[shndx];
212 const symbol_ptr = elf_file.symbol(self.gnu_eh_frame_hdr_index.?);263 allocSymbol(self, self.gnu_eh_frame_hdr_index.?, shdr.sh_addr, shndx, elf_file);
213 symbol_ptr.value = @intCast(shdr.sh_addr);
214 symbol_ptr.output_section_index = shndx;
215 }264 }
216265
217 // __rela_iplt_start, __rela_iplt_end266 // __rela_iplt_start, __rela_iplt_end
...@@ -220,32 +269,41 @@ pub fn allocateSymbols(self: *LinkerDefined, elf_file: *Elf) void {...@@ -220,32 +269,41 @@ pub fn allocateSymbols(self: *LinkerDefined, elf_file: *Elf) void {
220 const shdr = &elf_file.shdrs.items[shndx];269 const shdr = &elf_file.shdrs.items[shndx];
221 const end_addr = shdr.sh_addr + shdr.sh_size;270 const end_addr = shdr.sh_addr + shdr.sh_size;
222 const start_addr = end_addr - elf_file.calcNumIRelativeRelocs() * @sizeOf(elf.Elf64_Rela);271 const start_addr = end_addr - elf_file.calcNumIRelativeRelocs() * @sizeOf(elf.Elf64_Rela);
223 const start_sym = elf_file.symbol(self.rela_iplt_start_index.?);272 allocSymbol(self, self.rela_iplt_start_index.?, start_addr, shndx, elf_file);
224 const end_sym = elf_file.symbol(self.rela_iplt_end_index.?);273 allocSymbol(self, self.rela_iplt_end_index.?, end_addr, shndx, elf_file);
225 start_sym.value = @intCast(start_addr);
226 start_sym.output_section_index = shndx;
227 end_sym.value = @intCast(end_addr);
228 end_sym.output_section_index = shndx;
229 }274 }
230275
231 // _end276 // _end
232 {277 {
233 const end_symbol = elf_file.symbol(self.end_index.?);278 var value: u64 = 0;
279 var osec: u32 = 0;
234 for (elf_file.shdrs.items, 0..) |shdr, shndx| {280 for (elf_file.shdrs.items, 0..) |shdr, shndx| {
235 if (shdr.sh_flags & elf.SHF_ALLOC != 0) {281 if (shdr.sh_flags & elf.SHF_ALLOC != 0) {
236 end_symbol.value = @intCast(shdr.sh_addr + shdr.sh_size);282 value = shdr.sh_addr + shdr.sh_size;
237 end_symbol.output_section_index = @intCast(shndx);283 osec = @intCast(shndx);
238 }284 }
239 }285 }
286 allocSymbol(self, self.end_index.?, value, osec, elf_file);
287 }
288
289 // __global_pointer$
290 if (self.global_pointer_index) |index| {
291 const value, const osec = if (elf_file.sectionByName(".sdata")) |shndx| .{
292 elf_file.shdrs.items[shndx].sh_addr + 0x800,
293 shndx,
294 } else .{ 0, 0 };
295 allocSymbol(self, index, value, osec, elf_file);
240 }296 }
241297
242 // __start_*, __stop_*298 // __start_*, __stop_*
243 {299 {
244 var index: usize = 0;300 var index: usize = 0;
245 while (index < self.start_stop_indexes.items.len) : (index += 2) {301 while (index < self.start_stop_indexes.items.len) : (index += 2) {
246 const start = elf_file.symbol(self.start_stop_indexes.items[index]);302 const start_ref = self.resolveSymbol(self.start_stop_indexes.items[index], elf_file);
303 const start = elf_file.symbol(start_ref).?;
247 const name = start.name(elf_file);304 const name = start.name(elf_file);
248 const stop = elf_file.symbol(self.start_stop_indexes.items[index + 1]);305 const stop_ref = self.resolveSymbol(self.start_stop_indexes.items[index + 1], elf_file);
306 const stop = elf_file.symbol(stop_ref).?;
249 const shndx = elf_file.sectionByName(name["__start_".len..]).?;307 const shndx = elf_file.sectionByName(name["__start_".len..]).?;
250 const shdr = &elf_file.shdrs.items[shndx];308 const shdr = &elf_file.shdrs.items[shndx];
251 start.value = @intCast(shdr.sh_addr);309 start.value = @intCast(shdr.sh_addr);
...@@ -254,47 +312,30 @@ pub fn allocateSymbols(self: *LinkerDefined, elf_file: *Elf) void {...@@ -254,47 +312,30 @@ pub fn allocateSymbols(self: *LinkerDefined, elf_file: *Elf) void {
254 stop.output_section_index = shndx;312 stop.output_section_index = shndx;
255 }313 }
256 }314 }
257
258 // __global_pointer$
259 if (self.global_pointer_index) |index| {
260 const sym = elf_file.symbol(index);
261 if (elf_file.sectionByName(".sdata")) |shndx| {
262 const shdr = elf_file.shdrs.items[shndx];
263 sym.value = @intCast(shdr.sh_addr + 0x800);
264 sym.output_section_index = shndx;
265 } else {
266 sym.value = 0;
267 sym.output_section_index = 0;
268 }
269 }
270}
271
272pub fn globals(self: LinkerDefined) []const Symbol.Index {
273 return self.symbols.items;
274}315}
275316
276pub fn updateSymtabSize(self: *LinkerDefined, elf_file: *Elf) !void {317pub fn updateSymtabSize(self: *LinkerDefined, elf_file: *Elf) void {
277 for (self.globals()) |global_index| {318 for (self.symbols.items, self.symbols_resolver.items) |*global, resolv| {
278 const global = elf_file.symbol(global_index);319 const ref = elf_file.resolver.get(resolv).?;
279 const file_ptr = global.file(elf_file) orelse continue;320 const ref_sym = elf_file.symbol(ref) orelse continue;
280 if (file_ptr.index() != self.index) continue;321 if (ref_sym.file(elf_file).?.index() != self.index) continue;
281 global.flags.output_symtab = true;322 global.flags.output_symtab = true;
282 if (global.isLocal(elf_file)) {323 if (global.isLocal(elf_file)) {
283 try global.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file);324 global.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file);
284 self.output_symtab_ctx.nlocals += 1;325 self.output_symtab_ctx.nlocals += 1;
285 } else {326 } else {
286 try global.addExtra(.{ .symtab = self.output_symtab_ctx.nglobals }, elf_file);327 global.addExtra(.{ .symtab = self.output_symtab_ctx.nglobals }, elf_file);
287 self.output_symtab_ctx.nglobals += 1;328 self.output_symtab_ctx.nglobals += 1;
288 }329 }
289 self.output_symtab_ctx.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1;330 self.output_symtab_ctx.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1;
290 }331 }
291}332}
292333
293pub fn writeSymtab(self: LinkerDefined, elf_file: *Elf) void {334pub fn writeSymtab(self: *LinkerDefined, elf_file: *Elf) void {
294 for (self.globals()) |global_index| {335 for (self.symbols.items, self.symbols_resolver.items) |global, resolv| {
295 const global = elf_file.symbol(global_index);336 const ref = elf_file.resolver.get(resolv).?;
296 const file_ptr = global.file(elf_file) orelse continue;337 const ref_sym = elf_file.symbol(ref) orelse continue;
297 if (file_ptr.index() != self.index) continue;338 if (ref_sym.file(elf_file).?.index() != self.index) continue;
298 const idx = global.outputSymtabIndex(elf_file) orelse continue;339 const idx = global.outputSymtabIndex(elf_file) orelse continue;
299 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));340 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
300 elf_file.strtab.appendSliceAssumeCapacity(global.name(elf_file));341 elf_file.strtab.appendSliceAssumeCapacity(global.name(elf_file));
...@@ -305,15 +346,93 @@ pub fn writeSymtab(self: LinkerDefined, elf_file: *Elf) void {...@@ -305,15 +346,93 @@ pub fn writeSymtab(self: LinkerDefined, elf_file: *Elf) void {
305 }346 }
306}347}
307348
349pub fn dynamicSymbol(self: LinkerDefined, elf_file: *Elf) ?*Symbol {
350 const index = self.dynamic_index orelse return null;
351 const resolv = self.resolveSymbol(index, elf_file);
352 return elf_file.symbol(resolv);
353}
354
355pub fn entrySymbol(self: LinkerDefined, elf_file: *Elf) ?*Symbol {
356 const index = self.entry_index orelse return null;
357 const resolv = self.resolveSymbol(index, elf_file);
358 return elf_file.symbol(resolv);
359}
360
308pub fn asFile(self: *LinkerDefined) File {361pub fn asFile(self: *LinkerDefined) File {
309 return .{ .linker_defined = self };362 return .{ .linker_defined = self };
310}363}
311364
365fn addString(self: *LinkerDefined, allocator: Allocator, str: []const u8) !u32 {
366 const off: u32 = @intCast(self.strtab.items.len);
367 try self.strtab.ensureUnusedCapacity(allocator, str.len + 1);
368 self.strtab.appendSliceAssumeCapacity(str);
369 self.strtab.appendAssumeCapacity(0);
370 return off;
371}
372
312pub fn getString(self: LinkerDefined, off: u32) [:0]const u8 {373pub fn getString(self: LinkerDefined, off: u32) [:0]const u8 {
313 assert(off < self.strtab.items.len);374 assert(off < self.strtab.items.len);
314 return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0);375 return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0);
315}376}
316377
378pub fn resolveSymbol(self: LinkerDefined, index: Symbol.Index, elf_file: *Elf) Elf.Ref {
379 const resolv = self.symbols_resolver.items[index];
380 return elf_file.resolver.get(resolv).?;
381}
382
383fn addSymbol(self: *LinkerDefined, allocator: Allocator) !Symbol.Index {
384 try self.symbols.ensureUnusedCapacity(allocator, 1);
385 return self.addSymbolAssumeCapacity();
386}
387
388fn addSymbolAssumeCapacity(self: *LinkerDefined) Symbol.Index {
389 const index: Symbol.Index = @intCast(self.symbols.items.len);
390 self.symbols.appendAssumeCapacity(.{ .file_index = self.index });
391 return index;
392}
393
394pub fn addSymbolExtra(self: *LinkerDefined, allocator: Allocator, extra: Symbol.Extra) !u32 {
395 const fields = @typeInfo(Symbol.Extra).Struct.fields;
396 try self.symbols_extra.ensureUnusedCapacity(allocator, fields.len);
397 return self.addSymbolExtraAssumeCapacity(extra);
398}
399
400pub fn addSymbolExtraAssumeCapacity(self: *LinkerDefined, extra: Symbol.Extra) u32 {
401 const index = @as(u32, @intCast(self.symbols_extra.items.len));
402 const fields = @typeInfo(Symbol.Extra).Struct.fields;
403 inline for (fields) |field| {
404 self.symbols_extra.appendAssumeCapacity(switch (field.type) {
405 u32 => @field(extra, field.name),
406 else => @compileError("bad field type"),
407 });
408 }
409 return index;
410}
411
412pub fn symbolExtra(self: *LinkerDefined, index: u32) Symbol.Extra {
413 const fields = @typeInfo(Symbol.Extra).Struct.fields;
414 var i: usize = index;
415 var result: Symbol.Extra = undefined;
416 inline for (fields) |field| {
417 @field(result, field.name) = switch (field.type) {
418 u32 => self.symbols_extra.items[i],
419 else => @compileError("bad field type"),
420 };
421 i += 1;
422 }
423 return result;
424}
425
426pub fn setSymbolExtra(self: *LinkerDefined, index: u32, extra: Symbol.Extra) void {
427 const fields = @typeInfo(Symbol.Extra).Struct.fields;
428 inline for (fields, 0..) |field, i| {
429 self.symbols_extra.items[index + i] = switch (field.type) {
430 u32 => @field(extra, field.name),
431 else => @compileError("bad field type"),
432 };
433 }
434}
435
317pub fn fmtSymtab(self: *LinkerDefined, elf_file: *Elf) std.fmt.Formatter(formatSymtab) {436pub fn fmtSymtab(self: *LinkerDefined, elf_file: *Elf) std.fmt.Formatter(formatSymtab) {
318 return .{ .data = .{437 return .{ .data = .{
319 .self = self,438 .self = self,
...@@ -334,10 +453,16 @@ fn formatSymtab(...@@ -334,10 +453,16 @@ fn formatSymtab(
334) !void {453) !void {
335 _ = unused_fmt_string;454 _ = unused_fmt_string;
336 _ = options;455 _ = options;
456 const self = ctx.self;
457 const elf_file = ctx.elf_file;
337 try writer.writeAll(" globals\n");458 try writer.writeAll(" globals\n");
338 for (ctx.self.globals()) |index| {459 for (self.symbols.items, 0..) |sym, i| {
339 const global = ctx.elf_file.symbol(index);460 const ref = self.resolveSymbol(@intCast(i), elf_file);
340 try writer.print(" {}\n", .{global.fmt(ctx.elf_file)});461 if (elf_file.symbol(ref)) |ref_sym| {
462 try writer.print(" {}\n", .{ref_sym.fmt(elf_file)});
463 } else {
464 try writer.print(" {s} : unclaimed\n", .{sym.name(elf_file)});
465 }
341 }466 }
342}467}
343468
src/link/Elf/Object.zig+232-154
...@@ -9,7 +9,9 @@ shdrs: std.ArrayListUnmanaged(elf.Elf64_Shdr) = .{},...@@ -9,7 +9,9 @@ shdrs: std.ArrayListUnmanaged(elf.Elf64_Shdr) = .{},
9symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},9symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
10strtab: std.ArrayListUnmanaged(u8) = .{},10strtab: std.ArrayListUnmanaged(u8) = .{},
11first_global: ?Symbol.Index = null,11first_global: ?Symbol.Index = null,
12symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},12symbols: std.ArrayListUnmanaged(Symbol) = .{},
13symbols_extra: std.ArrayListUnmanaged(u32) = .{},
14symbols_resolver: std.ArrayListUnmanaged(Elf.SymbolResolver.Index) = .{},
13relocs: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{},15relocs: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{},
1416
15atoms: std.ArrayListUnmanaged(Atom) = .{},17atoms: std.ArrayListUnmanaged(Atom) = .{},
...@@ -51,6 +53,8 @@ pub fn deinit(self: *Object, allocator: Allocator) void {...@@ -51,6 +53,8 @@ pub fn deinit(self: *Object, allocator: Allocator) void {
51 self.symtab.deinit(allocator);53 self.symtab.deinit(allocator);
52 self.strtab.deinit(allocator);54 self.strtab.deinit(allocator);
53 self.symbols.deinit(allocator);55 self.symbols.deinit(allocator);
56 self.symbols_extra.deinit(allocator);
57 self.symbols_resolver.deinit(allocator);
54 self.atoms.deinit(allocator);58 self.atoms.deinit(allocator);
55 self.atoms_indexes.deinit(allocator);59 self.atoms_indexes.deinit(allocator);
56 self.atoms_extra.deinit(allocator);60 self.atoms_extra.deinit(allocator);
...@@ -80,7 +84,7 @@ pub fn parse(self: *Object, elf_file: *Elf) !void {...@@ -80,7 +84,7 @@ pub fn parse(self: *Object, elf_file: *Elf) !void {
80 try self.atoms.append(gpa, .{ .extra_index = try self.addAtomExtra(gpa, .{}) });84 try self.atoms.append(gpa, .{ .extra_index = try self.addAtomExtra(gpa, .{}) });
8185
82 try self.initAtoms(gpa, handle, elf_file);86 try self.initAtoms(gpa, handle, elf_file);
83 try self.initSymtab(gpa, elf_file);87 try self.initSymbols(gpa, elf_file);
8488
85 for (self.shdrs.items, 0..) |shdr, i| {89 for (self.shdrs.items, 0..) |shdr, i| {
86 const atom_ptr = self.atom(self.atoms_indexes.items[i]) orelse continue;90 const atom_ptr = self.atom(self.atoms_indexes.items[i]) orelse continue;
...@@ -374,29 +378,29 @@ fn skipShdr(self: *Object, index: u32, elf_file: *Elf) bool {...@@ -374,29 +378,29 @@ fn skipShdr(self: *Object, index: u32, elf_file: *Elf) bool {
374 return ignore;378 return ignore;
375}379}
376380
377fn initSymtab(self: *Object, allocator: Allocator, elf_file: *Elf) !void {381fn initSymbols(self: *Object, allocator: Allocator, elf_file: *Elf) !void {
378 const first_global = self.first_global orelse self.symtab.items.len;382 const first_global = self.first_global orelse self.symtab.items.len;
383 const nglobals = self.symtab.items.len - first_global;
379384
380 try self.symbols.ensureTotalCapacityPrecise(allocator, self.symtab.items.len);385 try self.symbols.ensureTotalCapacityPrecise(allocator, self.symtab.items.len);
381386 try self.symbols_extra.ensureTotalCapacityPrecise(allocator, self.symtab.items.len * @sizeOf(Symbol.Extra));
382 for (self.symtab.items[0..first_global], 0..) |sym, i| {387 try self.symbols_resolver.ensureTotalCapacityPrecise(allocator, nglobals);
383 const index = try elf_file.addSymbol();388 self.symbols_resolver.resize(allocator, nglobals) catch unreachable;
384 self.symbols.appendAssumeCapacity(index);389 @memset(self.symbols_resolver.items, 0);
385 const sym_ptr = elf_file.symbol(index);390
391 for (self.symtab.items, 0..) |sym, i| {
392 const index = self.addSymbolAssumeCapacity();
393 const sym_ptr = &self.symbols.items[index];
386 sym_ptr.value = @intCast(sym.st_value);394 sym_ptr.value = @intCast(sym.st_value);
387 sym_ptr.name_offset = sym.st_name;395 sym_ptr.name_offset = sym.st_name;
388 sym_ptr.esym_index = @as(u32, @intCast(i));396 sym_ptr.esym_index = @intCast(i);
389 sym_ptr.file_index = self.index;397 sym_ptr.extra_index = self.addSymbolExtraAssumeCapacity(.{});
390 if (sym.st_shndx != elf.SHN_ABS) {398 sym_ptr.version_index = if (i >= first_global) elf_file.default_sym_version else elf.VER_NDX_LOCAL;
399 sym_ptr.flags.weak = sym.st_bind() == elf.STB_WEAK;
400 if (sym.st_shndx != elf.SHN_ABS and sym.st_shndx != elf.SHN_COMMON) {
391 sym_ptr.ref = .{ .index = self.atoms_indexes.items[sym.st_shndx], .file = self.index };401 sym_ptr.ref = .{ .index = self.atoms_indexes.items[sym.st_shndx], .file = self.index };
392 }402 }
393 }403 }
394
395 for (self.symtab.items[first_global..]) |sym| {
396 const name = self.getString(sym.st_name);
397 const gop = try elf_file.getOrPutGlobal(name);
398 self.symbols.addOneAssumeCapacity().* = gop.index;
399 }
400}404}
401405
402fn parseEhFrame(self: *Object, allocator: Allocator, handle: std.fs.File, shndx: u32, elf_file: *Elf) !void {406fn parseEhFrame(self: *Object, allocator: Allocator, handle: std.fs.File, shndx: u32, elf_file: *Elf) !void {
...@@ -543,7 +547,7 @@ pub fn scanRelocs(self: *Object, elf_file: *Elf, undefs: anytype) !void {...@@ -543,7 +547,7 @@ pub fn scanRelocs(self: *Object, elf_file: *Elf, undefs: anytype) !void {
543547
544 for (self.cies.items) |cie| {548 for (self.cies.items) |cie| {
545 for (cie.relocs(elf_file)) |rel| {549 for (cie.relocs(elf_file)) |rel| {
546 const sym = elf_file.symbol(self.symbols.items[rel.r_sym()]);550 const sym = elf_file.symbol(self.resolveSymbol(rel.r_sym(), elf_file)).?;
547 if (sym.flags.import) {551 if (sym.flags.import) {
548 if (sym.type(elf_file) != elf.STT_FUNC)552 if (sym.type(elf_file) != elf.STT_FUNC)
549 // TODO convert into an error553 // TODO convert into an error
...@@ -557,49 +561,47 @@ pub fn scanRelocs(self: *Object, elf_file: *Elf, undefs: anytype) !void {...@@ -557,49 +561,47 @@ pub fn scanRelocs(self: *Object, elf_file: *Elf, undefs: anytype) !void {
557 }561 }
558}562}
559563
560pub fn resolveSymbols(self: *Object, elf_file: *Elf) void {564pub fn resolveSymbols(self: *Object, elf_file: *Elf) !void {
561 const first_global = self.first_global orelse return;565 const gpa = elf_file.base.comp.gpa;
562 for (self.globals(), 0..) |index, i| {
563 const esym_index = @as(Symbol.Index, @intCast(first_global + i));
564 const esym = self.symtab.items[esym_index];
565
566 if (esym.st_shndx == elf.SHN_UNDEF) continue;
567566
568 if (esym.st_shndx != elf.SHN_ABS and esym.st_shndx != elf.SHN_COMMON) {567 const first_global = self.first_global orelse return;
568 for (self.globals(), first_global..) |_, i| {
569 const esym = self.symtab.items[i];
570 if (esym.st_shndx != elf.SHN_ABS and esym.st_shndx != elf.SHN_COMMON and esym.st_shndx != elf.SHN_UNDEF) {
569 const atom_index = self.atoms_indexes.items[esym.st_shndx];571 const atom_index = self.atoms_indexes.items[esym.st_shndx];
570 const atom_ptr = self.atom(atom_index) orelse continue;572 const atom_ptr = self.atom(atom_index) orelse continue;
571 if (!atom_ptr.alive) continue;573 if (!atom_ptr.alive) continue;
572 }574 }
573575
574 const global = elf_file.symbol(index);576 const resolv = &self.symbols_resolver.items[i - first_global];
575 if (self.asFile().symbolRank(esym, !self.alive) < global.symbolRank(elf_file)) {577 const gop = try elf_file.resolver.getOrPut(gpa, .{
576 switch (esym.st_shndx) {578 .index = @intCast(i),
577 elf.SHN_ABS, elf.SHN_COMMON => {},579 .file = self.index,
578 else => global.ref = .{580 }, elf_file);
579 .index = self.atoms_indexes.items[esym.st_shndx],581 if (!gop.found_existing) {
580 .file = self.index,582 gop.ref.* = .{ .index = 0, .file = 0 };
581 },583 }
582 }584 resolv.* = gop.index;
583 global.value = @intCast(esym.st_value);585
584 global.esym_index = esym_index;586 if (esym.st_shndx == elf.SHN_UNDEF) continue;
585 global.file_index = self.index;587 if (elf_file.symbol(gop.ref.*) == null) {
586 global.version_index = elf_file.default_sym_version;588 gop.ref.* = .{ .index = @intCast(i), .file = self.index };
587 if (esym.st_bind() == elf.STB_WEAK) global.flags.weak = true;589 continue;
590 }
591
592 if (self.asFile().symbolRank(esym, !self.alive) < elf_file.symbol(gop.ref.*).?.symbolRank(elf_file)) {
593 gop.ref.* = .{ .index = @intCast(i), .file = self.index };
588 }594 }
589 }595 }
590}596}
591597
592pub fn claimUnresolved(self: *Object, elf_file: *Elf) void {598pub fn claimUnresolved(self: *Object, elf_file: *Elf) void {
593 const first_global = self.first_global orelse return;599 const first_global = self.first_global orelse return;
594 for (self.globals(), 0..) |index, i| {600 for (self.globals(), 0..) |*sym, i| {
595 const esym_index = @as(u32, @intCast(first_global + i));601 const esym_index = @as(u32, @intCast(first_global + i));
596 const esym = self.symtab.items[esym_index];602 const esym = self.symtab.items[esym_index];
597 if (esym.st_shndx != elf.SHN_UNDEF) continue;603 if (esym.st_shndx != elf.SHN_UNDEF) continue;
598604 if (elf_file.symbol(self.resolveSymbol(esym_index, elf_file)) != null) continue;
599 const global = elf_file.symbol(index);
600 if (global.file(elf_file)) |_| {
601 if (global.elfSym(elf_file).st_shndx != elf.SHN_UNDEF) continue;
602 }
603605
604 const is_import = blk: {606 const is_import = blk: {
605 if (!elf_file.isEffectivelyDynLib()) break :blk false;607 if (!elf_file.isEffectivelyDynLib()) break :blk false;
...@@ -608,45 +610,48 @@ pub fn claimUnresolved(self: *Object, elf_file: *Elf) void {...@@ -608,45 +610,48 @@ pub fn claimUnresolved(self: *Object, elf_file: *Elf) void {
608 break :blk true;610 break :blk true;
609 };611 };
610612
611 global.value = 0;613 sym.value = 0;
612 global.ref = .{ .index = 0, .file = 0 };614 sym.ref = .{ .index = 0, .file = 0 };
613 global.esym_index = esym_index;615 sym.esym_index = esym_index;
614 global.file_index = self.index;616 sym.file_index = self.index;
615 global.version_index = if (is_import) elf.VER_NDX_LOCAL else elf_file.default_sym_version;617 sym.version_index = if (is_import) elf.VER_NDX_LOCAL else elf_file.default_sym_version;
616 global.flags.import = is_import;618 sym.flags.import = is_import;
619
620 const idx = self.symbols_resolver.items[i];
621 elf_file.resolver.values.items[idx - 1] = .{ .index = esym_index, .file = self.index };
617 }622 }
618}623}
619624
620pub fn claimUnresolvedObject(self: *Object, elf_file: *Elf) void {625pub fn claimUnresolvedObject(self: *Object, elf_file: *Elf) void {
621 const first_global = self.first_global orelse return;626 const first_global = self.first_global orelse return;
622 for (self.globals(), 0..) |index, i| {627 for (self.globals(), 0..) |*sym, i| {
623 const esym_index = @as(u32, @intCast(first_global + i));628 const esym_index = @as(u32, @intCast(first_global + i));
624 const esym = self.symtab.items[esym_index];629 const esym = self.symtab.items[esym_index];
625 if (esym.st_shndx != elf.SHN_UNDEF) continue;630 if (esym.st_shndx != elf.SHN_UNDEF) continue;
631 if (elf_file.symbol(self.resolveSymbol(esym_index, elf_file)) != null) continue;
626632
627 const global = elf_file.symbol(index);633 sym.value = 0;
628 if (global.file(elf_file)) |file| {634 sym.ref = .{ .index = 0, .file = 0 };
629 if (global.elfSym(elf_file).st_shndx != elf.SHN_UNDEF or file.index() <= self.index) continue;635 sym.esym_index = esym_index;
630 }636 sym.file_index = self.index;
631637
632 global.value = 0;638 const idx = self.symbols_resolver.items[i];
633 global.ref = .{ .index = 0, .file = 0 };639 elf_file.resolver.values.items[idx - 1] = .{ .index = esym_index, .file = self.index };
634 global.esym_index = esym_index;
635 global.file_index = self.index;
636 }640 }
637}641}
638642
639pub fn markLive(self: *Object, elf_file: *Elf) void {643pub fn markLive(self: *Object, elf_file: *Elf) void {
640 const first_global = self.first_global orelse return;644 const first_global = self.first_global orelse return;
641 for (self.globals(), 0..) |index, i| {645 for (0..self.globals().len) |i| {
642 const sym_idx = first_global + i;646 const esym_idx = first_global + i;
643 const sym = self.symtab.items[sym_idx];647 const esym = self.symtab.items[esym_idx];
644 if (sym.st_bind() == elf.STB_WEAK) continue;648 if (esym.st_bind() == elf.STB_WEAK) continue;
645649
646 const global = elf_file.symbol(index);650 const ref = self.resolveSymbol(@intCast(esym_idx), elf_file);
647 const file = global.file(elf_file) orelse continue;651 const sym = elf_file.symbol(ref) orelse continue;
648 const should_keep = sym.st_shndx == elf.SHN_UNDEF or652 const file = sym.file(elf_file).?;
649 (sym.st_shndx == elf.SHN_COMMON and global.elfSym(elf_file).st_shndx != elf.SHN_COMMON);653 const should_keep = esym.st_shndx == elf.SHN_UNDEF or
654 (esym.st_shndx == elf.SHN_COMMON and sym.elfSym(elf_file).st_shndx != elf.SHN_COMMON);
650 if (should_keep and !file.isAlive()) {655 if (should_keep and !file.isAlive()) {
651 file.setAlive();656 file.setAlive();
652 file.markLive(elf_file);657 file.markLive(elf_file);
...@@ -664,26 +669,50 @@ pub fn markEhFrameAtomsDead(self: *Object, elf_file: *Elf) void {...@@ -664,26 +669,50 @@ pub fn markEhFrameAtomsDead(self: *Object, elf_file: *Elf) void {
664 }669 }
665}670}
666671
672pub fn markImportsExports(self: *Object, elf_file: *Elf) void {
673 const first_global = self.first_global orelse return;
674 for (0..self.globals().len) |i| {
675 const idx = first_global + i;
676 const ref = self.resolveSymbol(@intCast(idx), elf_file);
677 const sym = elf_file.symbol(ref) orelse continue;
678 const file = sym.file(elf_file).?;
679 if (sym.version_index == elf.VER_NDX_LOCAL) continue;
680 const vis = @as(elf.STV, @enumFromInt(sym.elfSym(elf_file).st_other));
681 if (vis == .HIDDEN) continue;
682 if (file == .shared_object and !sym.isAbs(elf_file)) {
683 sym.flags.import = true;
684 continue;
685 }
686 if (file.index() == self.index) {
687 sym.flags.@"export" = true;
688 if (elf_file.isEffectivelyDynLib() and vis != .PROTECTED) {
689 sym.flags.import = true;
690 }
691 }
692 }
693}
694
667pub fn checkDuplicates(self: *Object, dupes: anytype, elf_file: *Elf) error{OutOfMemory}!void {695pub fn checkDuplicates(self: *Object, dupes: anytype, elf_file: *Elf) error{OutOfMemory}!void {
668 const first_global = self.first_global orelse return;696 const first_global = self.first_global orelse return;
669 for (self.globals(), 0..) |index, i| {697 for (0..self.globals().len) |i| {
670 const sym_idx = first_global + i;698 const esym_idx = first_global + i;
671 const sym = self.symtab.items[sym_idx];699 const esym = self.symtab.items[esym_idx];
672 const global = elf_file.symbol(index);700 const ref = self.resolveSymbol(@intCast(esym_idx), elf_file);
673 const global_file = global.file(elf_file) orelse continue;701 const ref_sym = elf_file.symbol(ref) orelse continue;
674702 const ref_file = ref_sym.file(elf_file).?;
675 if (self.index == global_file.index() or703
676 sym.st_shndx == elf.SHN_UNDEF or704 if (self.index == ref_file.index() or
677 sym.st_bind() == elf.STB_WEAK or705 esym.st_shndx == elf.SHN_UNDEF or
678 sym.st_shndx == elf.SHN_COMMON) continue;706 esym.st_bind() == elf.STB_WEAK or
679707 esym.st_shndx == elf.SHN_COMMON) continue;
680 if (sym.st_shndx != elf.SHN_ABS) {708
681 const atom_index = self.atoms_indexes.items[sym.st_shndx];709 if (esym.st_shndx != elf.SHN_ABS) {
710 const atom_index = self.atoms_indexes.items[esym.st_shndx];
682 const atom_ptr = self.atom(atom_index) orelse continue;711 const atom_ptr = self.atom(atom_index) orelse continue;
683 if (!atom_ptr.alive) continue;712 if (!atom_ptr.alive) continue;
684 }713 }
685714
686 const gop = try dupes.getOrPut(index);715 const gop = try dupes.getOrPut(self.symbols_resolver.items[i]);
687 if (!gop.found_existing) {716 if (!gop.found_existing) {
688 gop.value_ptr.* = .{};717 gop.value_ptr.* = .{};
689 }718 }
...@@ -813,9 +842,7 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void {...@@ -813,9 +842,7 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void {
813 }842 }
814843
815 for (self.symtab.items, 0..) |*esym, idx| {844 for (self.symtab.items, 0..) |*esym, idx| {
816 const sym_index = self.symbols.items[idx];845 const sym = &self.symbols.items[idx];
817 const sym = elf_file.symbol(sym_index);
818
819 if (esym.st_shndx == elf.SHN_COMMON or esym.st_shndx == elf.SHN_UNDEF or esym.st_shndx == elf.SHN_ABS) continue;846 if (esym.st_shndx == elf.SHN_COMMON or esym.st_shndx == elf.SHN_UNDEF or esym.st_shndx == elf.SHN_ABS) continue;
820847
821 const imsec_index = self.input_merge_sections_indexes.items[esym.st_shndx];848 const imsec_index = self.input_merge_sections_indexes.items[esym.st_shndx];
...@@ -854,22 +881,20 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void {...@@ -854,22 +881,20 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void {
854 return error.MalformedObject;881 return error.MalformedObject;
855 };882 };
856883
857 const out_sym_idx: u64 = @intCast(self.symbols.items.len);884 const sym_index = try self.addSymbol(gpa);
858 try self.symbols.ensureUnusedCapacity(gpa, 1);885 const sym = &self.symbols.items[sym_index];
859 const name = try std.fmt.allocPrint(gpa, "{s}$subsection{d}", .{ msec.name(elf_file), res.msub_index });886 const name = try std.fmt.allocPrint(gpa, "{s}$subsection{d}", .{ msec.name(elf_file), res.msub_index });
860 defer gpa.free(name);887 defer gpa.free(name);
861 const sym_index = try elf_file.addSymbol();
862 const sym = elf_file.symbol(sym_index);
863 sym.* = .{888 sym.* = .{
864 .value = @bitCast(@as(i64, @intCast(res.offset)) - rel.r_addend),889 .value = @bitCast(@as(i64, @intCast(res.offset)) - rel.r_addend),
865 .name_offset = try self.addString(gpa, name),890 .name_offset = try self.addString(gpa, name),
866 .esym_index = rel.r_sym(),891 .esym_index = rel.r_sym(),
867 .file_index = self.index,892 .file_index = self.index,
893 .extra_index = try self.addSymbolExtra(gpa, .{}),
868 };894 };
869 sym.ref = .{ .index = res.msub_index, .file = imsec.merge_section_index };895 sym.ref = .{ .index = res.msub_index, .file = imsec.merge_section_index };
870 sym.flags.merge_subsection = true;896 sym.flags.merge_subsection = true;
871 self.symbols.addOneAssumeCapacity().* = sym_index;897 rel.r_info = (@as(u64, @intCast(sym_index)) << 32) | rel.r_type();
872 rel.r_info = (out_sym_idx << 32) | rel.r_type();
873 }898 }
874 }899 }
875}900}
...@@ -878,27 +903,16 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void {...@@ -878,27 +903,16 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void {
878/// play nicely with the rest of the system.903/// play nicely with the rest of the system.
879pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {904pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {
880 const first_global = self.first_global orelse return;905 const first_global = self.first_global orelse return;
881 for (self.globals(), 0..) |index, i| {906 for (self.globals(), self.symbols_resolver.items, 0..) |*sym, resolv, i| {
882 const sym_idx = @as(u32, @intCast(first_global + i));907 const esym_idx = @as(u32, @intCast(first_global + i));
883 const this_sym = self.symtab.items[sym_idx];908 const esym = self.symtab.items[esym_idx];
884 if (this_sym.st_shndx != elf.SHN_COMMON) continue;909 if (esym.st_shndx != elf.SHN_COMMON) continue;
885910 if (elf_file.resolver.get(resolv).?.file != self.index) continue;
886 const global = elf_file.symbol(index);
887 const global_file = global.file(elf_file).?;
888 if (global_file.index() != self.index) {
889 // if (elf_file.options.warn_common) {
890 // elf_file.base.warn("{}: multiple common symbols: {s}", .{
891 // self.fmtPath(),
892 // global.getName(elf_file),
893 // });
894 // }
895 continue;
896 }
897911
898 const comp = elf_file.base.comp;912 const comp = elf_file.base.comp;
899 const gpa = comp.gpa;913 const gpa = comp.gpa;
900914
901 const is_tls = global.type(elf_file) == elf.STT_TLS;915 const is_tls = sym.type(elf_file) == elf.STT_TLS;
902 const name = if (is_tls) ".tls_common" else ".common";916 const name = if (is_tls) ".tls_common" else ".common";
903 const name_offset = @as(u32, @intCast(self.strtab.items.len));917 const name_offset = @as(u32, @intCast(self.strtab.items.len));
904 try self.strtab.writer(gpa).print("{s}\x00", .{name});918 try self.strtab.writer(gpa).print("{s}\x00", .{name});
...@@ -907,7 +921,7 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {...@@ -907,7 +921,7 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {
907 if (is_tls) sh_flags |= elf.SHF_TLS;921 if (is_tls) sh_flags |= elf.SHF_TLS;
908 const shndx = @as(u32, @intCast(self.shdrs.items.len));922 const shndx = @as(u32, @intCast(self.shdrs.items.len));
909 const shdr = try self.shdrs.addOne(gpa);923 const shdr = try self.shdrs.addOne(gpa);
910 const sh_size = math.cast(usize, this_sym.st_size) orelse return error.Overflow;924 const sh_size = math.cast(usize, esym.st_size) orelse return error.Overflow;
911 shdr.* = .{925 shdr.* = .{
912 .sh_name = name_offset,926 .sh_name = name_offset,
913 .sh_type = elf.SHT_NOBITS,927 .sh_type = elf.SHT_NOBITS,
...@@ -917,21 +931,21 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {...@@ -917,21 +931,21 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {
917 .sh_size = sh_size,931 .sh_size = sh_size,
918 .sh_link = 0,932 .sh_link = 0,
919 .sh_info = 0,933 .sh_info = 0,
920 .sh_addralign = this_sym.st_value,934 .sh_addralign = esym.st_value,
921 .sh_entsize = 0,935 .sh_entsize = 0,
922 };936 };
923937
924 const atom_index = try self.addAtom(gpa, .{938 const atom_index = try self.addAtom(gpa, .{
925 .name = name_offset,939 .name = name_offset,
926 .shndx = shndx,940 .shndx = shndx,
927 .size = this_sym.st_size,941 .size = esym.st_size,
928 .alignment = Alignment.fromNonzeroByteUnits(this_sym.st_value),942 .alignment = Alignment.fromNonzeroByteUnits(esym.st_value),
929 });943 });
930 try self.atoms_indexes.append(gpa, atom_index);944 try self.atoms_indexes.append(gpa, atom_index);
931945
932 global.value = 0;946 sym.value = 0;
933 global.ref = .{ .index = atom_index, .file = self.index };947 sym.ref = .{ .index = atom_index, .file = self.index };
934 global.flags.weak = false;948 sym.flags.weak = false;
935 }949 }
936}950}
937951
...@@ -1073,7 +1087,7 @@ pub fn writeAr(self: Object, elf_file: *Elf, writer: anytype) !void {...@@ -1073,7 +1087,7 @@ pub fn writeAr(self: Object, elf_file: *Elf, writer: anytype) !void {
1073 try writer.writeAll(data);1087 try writer.writeAll(data);
1074}1088}
10751089
1076pub fn updateSymtabSize(self: *Object, elf_file: *Elf) !void {1090pub fn updateSymtabSize(self: *Object, elf_file: *Elf) void {
1077 const isAlive = struct {1091 const isAlive = struct {
1078 fn isAlive(sym: *const Symbol, ctx: *Elf) bool {1092 fn isAlive(sym: *const Symbol, ctx: *Elf) bool {
1079 if (sym.mergeSubsection(ctx)) |msub| return msub.alive;1093 if (sym.mergeSubsection(ctx)) |msub| return msub.alive;
...@@ -1082,8 +1096,7 @@ pub fn updateSymtabSize(self: *Object, elf_file: *Elf) !void {...@@ -1082,8 +1096,7 @@ pub fn updateSymtabSize(self: *Object, elf_file: *Elf) !void {
1082 }1096 }
1083 }.isAlive;1097 }.isAlive;
10841098
1085 for (self.locals()) |local_index| {1099 for (self.locals()) |*local| {
1086 const local = elf_file.symbol(local_index);
1087 if (!isAlive(local, elf_file)) continue;1100 if (!isAlive(local, elf_file)) continue;
1088 const esym = local.elfSym(elf_file);1101 const esym = local.elfSym(elf_file);
1089 switch (esym.st_type()) {1102 switch (esym.st_type()) {
...@@ -1092,31 +1105,30 @@ pub fn updateSymtabSize(self: *Object, elf_file: *Elf) !void {...@@ -1092,31 +1105,30 @@ pub fn updateSymtabSize(self: *Object, elf_file: *Elf) !void {
1092 else => {},1105 else => {},
1093 }1106 }
1094 local.flags.output_symtab = true;1107 local.flags.output_symtab = true;
1095 try local.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file);1108 local.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file);
1096 self.output_symtab_ctx.nlocals += 1;1109 self.output_symtab_ctx.nlocals += 1;
1097 self.output_symtab_ctx.strsize += @as(u32, @intCast(local.name(elf_file).len)) + 1;1110 self.output_symtab_ctx.strsize += @as(u32, @intCast(local.name(elf_file).len)) + 1;
1098 }1111 }
10991112
1100 for (self.globals()) |global_index| {1113 for (self.globals(), self.symbols_resolver.items) |*global, resolv| {
1101 const global = elf_file.symbol(global_index);1114 const ref = elf_file.resolver.values.items[resolv - 1];
1102 const file_ptr = global.file(elf_file) orelse continue;1115 const ref_sym = elf_file.symbol(ref) orelse continue;
1103 if (file_ptr.index() != self.index) continue;1116 if (ref_sym.file(elf_file).?.index() != self.index) continue;
1104 if (!isAlive(global, elf_file)) continue;1117 if (!isAlive(global, elf_file)) continue;
1105 global.flags.output_symtab = true;1118 global.flags.output_symtab = true;
1106 if (global.isLocal(elf_file)) {1119 if (global.isLocal(elf_file)) {
1107 try global.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file);1120 global.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file);
1108 self.output_symtab_ctx.nlocals += 1;1121 self.output_symtab_ctx.nlocals += 1;
1109 } else {1122 } else {
1110 try global.addExtra(.{ .symtab = self.output_symtab_ctx.nglobals }, elf_file);1123 global.addExtra(.{ .symtab = self.output_symtab_ctx.nglobals }, elf_file);
1111 self.output_symtab_ctx.nglobals += 1;1124 self.output_symtab_ctx.nglobals += 1;
1112 }1125 }
1113 self.output_symtab_ctx.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1;1126 self.output_symtab_ctx.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1;
1114 }1127 }
1115}1128}
11161129
1117pub fn writeSymtab(self: Object, elf_file: *Elf) void {1130pub fn writeSymtab(self: *Object, elf_file: *Elf) void {
1118 for (self.locals()) |local_index| {1131 for (self.locals()) |local| {
1119 const local = elf_file.symbol(local_index);
1120 const idx = local.outputSymtabIndex(elf_file) orelse continue;1132 const idx = local.outputSymtabIndex(elf_file) orelse continue;
1121 const out_sym = &elf_file.symtab.items[idx];1133 const out_sym = &elf_file.symtab.items[idx];
1122 out_sym.st_name = @intCast(elf_file.strtab.items.len);1134 out_sym.st_name = @intCast(elf_file.strtab.items.len);
...@@ -1125,10 +1137,10 @@ pub fn writeSymtab(self: Object, elf_file: *Elf) void {...@@ -1125,10 +1137,10 @@ pub fn writeSymtab(self: Object, elf_file: *Elf) void {
1125 local.setOutputSym(elf_file, out_sym);1137 local.setOutputSym(elf_file, out_sym);
1126 }1138 }
11271139
1128 for (self.globals()) |global_index| {1140 for (self.globals(), self.symbols_resolver.items) |global, resolv| {
1129 const global = elf_file.symbol(global_index);1141 const ref = elf_file.resolver.values.items[resolv - 1];
1130 const file_ptr = global.file(elf_file) orelse continue;1142 const ref_sym = elf_file.symbol(ref) orelse continue;
1131 if (file_ptr.index() != self.index) continue;1143 if (ref_sym.file(elf_file).?.index() != self.index) continue;
1132 const idx = global.outputSymtabIndex(elf_file) orelse continue;1144 const idx = global.outputSymtabIndex(elf_file) orelse continue;
1133 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));1145 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
1134 elf_file.strtab.appendSliceAssumeCapacity(global.name(elf_file));1146 elf_file.strtab.appendSliceAssumeCapacity(global.name(elf_file));
...@@ -1139,20 +1151,6 @@ pub fn writeSymtab(self: Object, elf_file: *Elf) void {...@@ -1139,20 +1151,6 @@ pub fn writeSymtab(self: Object, elf_file: *Elf) void {
1139 }1151 }
1140}1152}
11411153
1142pub fn locals(self: Object) []const Symbol.Index {
1143 if (self.symbols.items.len == 0) return &[0]Symbol.Index{};
1144 assert(self.symbols.items.len >= self.symtab.items.len);
1145 const end = self.first_global orelse self.symtab.items.len;
1146 return self.symbols.items[0..end];
1147}
1148
1149pub fn globals(self: Object) []const Symbol.Index {
1150 if (self.symbols.items.len == 0) return &[0]Symbol.Index{};
1151 assert(self.symbols.items.len >= self.symtab.items.len);
1152 const start = self.first_global orelse self.symtab.items.len;
1153 return self.symbols.items[start..self.symtab.items.len];
1154}
1155
1156/// Returns atom's code and optionally uncompresses data if required (for compressed sections).1154/// Returns atom's code and optionally uncompresses data if required (for compressed sections).
1157/// Caller owns the memory.1155/// Caller owns the memory.
1158pub fn codeDecompressAlloc(self: *Object, elf_file: *Elf, atom_index: Atom.Index) ![]u8 {1156pub fn codeDecompressAlloc(self: *Object, elf_file: *Elf, atom_index: Atom.Index) ![]u8 {
...@@ -1185,6 +1183,81 @@ pub fn codeDecompressAlloc(self: *Object, elf_file: *Elf, atom_index: Atom.Index...@@ -1185,6 +1183,81 @@ pub fn codeDecompressAlloc(self: *Object, elf_file: *Elf, atom_index: Atom.Index
1185 return data;1183 return data;
1186}1184}
11871185
1186fn locals(self: *Object) []Symbol {
1187 if (self.symbols.items.len == 0) return &[0]Symbol{};
1188 assert(self.symbols.items.len >= self.symtab.items.len);
1189 const end = self.first_global orelse self.symtab.items.len;
1190 return self.symbols.items[0..end];
1191}
1192
1193pub fn globals(self: *Object) []Symbol {
1194 if (self.symbols.items.len == 0) return &[0]Symbol{};
1195 assert(self.symbols.items.len >= self.symtab.items.len);
1196 const start = self.first_global orelse self.symtab.items.len;
1197 return self.symbols.items[start..self.symtab.items.len];
1198}
1199
1200pub fn resolveSymbol(self: Object, index: Symbol.Index, elf_file: *Elf) Elf.Ref {
1201 const start = self.first_global orelse self.symtab.items.len;
1202 const end = self.symtab.items.len;
1203 if (index < start or index >= end) return .{ .index = index, .file = self.index };
1204 const resolv = self.symbols_resolver.items[index - start];
1205 return elf_file.resolver.get(resolv).?;
1206}
1207
1208fn addSymbol(self: *Object, allocator: Allocator) !Symbol.Index {
1209 try self.symbols.ensureUnusedCapacity(allocator, 1);
1210 return self.addSymbolAssumeCapacity();
1211}
1212
1213fn addSymbolAssumeCapacity(self: *Object) Symbol.Index {
1214 const index: Symbol.Index = @intCast(self.symbols.items.len);
1215 self.symbols.appendAssumeCapacity(.{ .file_index = self.index });
1216 return index;
1217}
1218
1219pub fn addSymbolExtra(self: *Object, allocator: Allocator, extra: Symbol.Extra) !u32 {
1220 const fields = @typeInfo(Symbol.Extra).Struct.fields;
1221 try self.symbols_extra.ensureUnusedCapacity(allocator, fields.len);
1222 return self.addSymbolExtraAssumeCapacity(extra);
1223}
1224
1225pub fn addSymbolExtraAssumeCapacity(self: *Object, extra: Symbol.Extra) u32 {
1226 const index = @as(u32, @intCast(self.symbols_extra.items.len));
1227 const fields = @typeInfo(Symbol.Extra).Struct.fields;
1228 inline for (fields) |field| {
1229 self.symbols_extra.appendAssumeCapacity(switch (field.type) {
1230 u32 => @field(extra, field.name),
1231 else => @compileError("bad field type"),
1232 });
1233 }
1234 return index;
1235}
1236
1237pub fn symbolExtra(self: *Object, index: u32) Symbol.Extra {
1238 const fields = @typeInfo(Symbol.Extra).Struct.fields;
1239 var i: usize = index;
1240 var result: Symbol.Extra = undefined;
1241 inline for (fields) |field| {
1242 @field(result, field.name) = switch (field.type) {
1243 u32 => self.symbols_extra.items[i],
1244 else => @compileError("bad field type"),
1245 };
1246 i += 1;
1247 }
1248 return result;
1249}
1250
1251pub fn setSymbolExtra(self: *Object, index: u32, extra: Symbol.Extra) void {
1252 const fields = @typeInfo(Symbol.Extra).Struct.fields;
1253 inline for (fields, 0..) |field, i| {
1254 self.symbols_extra.items[index + i] = switch (field.type) {
1255 u32 => @field(extra, field.name),
1256 else => @compileError("bad field type"),
1257 };
1258 }
1259}
1260
1188pub fn asFile(self: *Object) File {1261pub fn asFile(self: *Object) File {
1189 return .{ .object = self };1262 return .{ .object = self };
1190}1263}
...@@ -1352,15 +1425,20 @@ fn formatSymtab(...@@ -1352,15 +1425,20 @@ fn formatSymtab(
1352 _ = unused_fmt_string;1425 _ = unused_fmt_string;
1353 _ = options;1426 _ = options;
1354 const object = ctx.object;1427 const object = ctx.object;
1428 const elf_file = ctx.elf_file;
1355 try writer.writeAll(" locals\n");1429 try writer.writeAll(" locals\n");
1356 for (object.locals()) |index| {1430 for (object.locals()) |sym| {
1357 const local = ctx.elf_file.symbol(index);1431 try writer.print(" {}\n", .{sym.fmt(elf_file)});
1358 try writer.print(" {}\n", .{local.fmt(ctx.elf_file)});
1359 }1432 }
1360 try writer.writeAll(" globals\n");1433 try writer.writeAll(" globals\n");
1361 for (object.globals()) |index| {1434 for (object.globals(), 0..) |sym, i| {
1362 const global = ctx.elf_file.symbol(index);1435 const first_global = object.first_global.?;
1363 try writer.print(" {}\n", .{global.fmt(ctx.elf_file)});1436 const ref = object.resolveSymbol(@intCast(i + first_global), elf_file);
1437 if (elf_file.symbol(ref)) |ref_sym| {
1438 try writer.print(" {}\n", .{ref_sym.fmt(elf_file)});
1439 } else {
1440 try writer.print(" {s} : unclaimed\n", .{sym.name(elf_file)});
1441 }
1364 }1442 }
1365}1443}
13661444
src/link/Elf/SharedObject.zig+163-62
...@@ -10,7 +10,10 @@ strtab: std.ArrayListUnmanaged(u8) = .{},...@@ -10,7 +10,10 @@ strtab: std.ArrayListUnmanaged(u8) = .{},
10versyms: std.ArrayListUnmanaged(elf.Elf64_Versym) = .{},10versyms: std.ArrayListUnmanaged(elf.Elf64_Versym) = .{},
11verstrings: std.ArrayListUnmanaged(u32) = .{},11verstrings: std.ArrayListUnmanaged(u32) = .{},
1212
13symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},13symbols: std.ArrayListUnmanaged(Symbol) = .{},
14symbols_extra: std.ArrayListUnmanaged(u32) = .{},
15symbols_resolver: std.ArrayListUnmanaged(Elf.SymbolResolver.Index) = .{},
16
14aliases: ?std.ArrayListUnmanaged(u32) = null,17aliases: ?std.ArrayListUnmanaged(u32) = null,
15dynamic_table: std.ArrayListUnmanaged(elf.Elf64_Dyn) = .{},18dynamic_table: std.ArrayListUnmanaged(elf.Elf64_Dyn) = .{},
1619
...@@ -38,6 +41,8 @@ pub fn deinit(self: *SharedObject, allocator: Allocator) void {...@@ -38,6 +41,8 @@ pub fn deinit(self: *SharedObject, allocator: Allocator) void {
38 self.versyms.deinit(allocator);41 self.versyms.deinit(allocator);
39 self.verstrings.deinit(allocator);42 self.verstrings.deinit(allocator);
40 self.symbols.deinit(allocator);43 self.symbols.deinit(allocator);
44 self.symbols_extra.deinit(allocator);
45 self.symbols_resolver.deinit(allocator);
41 if (self.aliases) |*aliases| aliases.deinit(allocator);46 if (self.aliases) |*aliases| aliases.deinit(allocator);
42 self.dynamic_table.deinit(allocator);47 self.dynamic_table.deinit(allocator);
43}48}
...@@ -129,7 +134,7 @@ pub fn parse(self: *SharedObject, elf_file: *Elf, handle: std.fs.File) !void {...@@ -129,7 +134,7 @@ pub fn parse(self: *SharedObject, elf_file: *Elf, handle: std.fs.File) !void {
129 .versym_sect_index = versym_sect_index,134 .versym_sect_index = versym_sect_index,
130 });135 });
131136
132 try self.initSymtab(elf_file, .{137 try self.initSymbols(elf_file, .{
133 .symtab = symtab,138 .symtab = symtab,
134 .strtab = strtab,139 .strtab = strtab,
135 });140 });
...@@ -188,16 +193,20 @@ fn parseVersions(self: *SharedObject, elf_file: *Elf, handle: std.fs.File, opts:...@@ -188,16 +193,20 @@ fn parseVersions(self: *SharedObject, elf_file: *Elf, handle: std.fs.File, opts:
188 }193 }
189}194}
190195
191fn initSymtab(self: *SharedObject, elf_file: *Elf, opts: struct {196fn initSymbols(self: *SharedObject, elf_file: *Elf, opts: struct {
192 symtab: []align(1) const elf.Elf64_Sym,197 symtab: []align(1) const elf.Elf64_Sym,
193 strtab: []const u8,198 strtab: []const u8,
194}) !void {199}) !void {
195 const comp = elf_file.base.comp;200 const gpa = elf_file.base.comp.gpa;
196 const gpa = comp.gpa;201 const nsyms = opts.symtab.len;
197202
198 try self.strtab.appendSlice(gpa, opts.strtab);203 try self.strtab.appendSlice(gpa, opts.strtab);
199 try self.symtab.ensureTotalCapacityPrecise(gpa, opts.symtab.len);204 try self.symtab.ensureTotalCapacityPrecise(gpa, nsyms);
200 try self.symbols.ensureTotalCapacityPrecise(gpa, opts.symtab.len);205 try self.symbols.ensureTotalCapacityPrecise(gpa, nsyms);
206 try self.symbols_extra.ensureTotalCapacityPrecise(gpa, nsyms * @sizeOf(Symbol.Extra));
207 try self.symbols_resolver.ensureTotalCapacityPrecise(gpa, nsyms);
208 self.symbols_resolver.resize(gpa, nsyms) catch unreachable;
209 @memset(self.symbols_resolver.items, 0);
201210
202 for (opts.symtab, 0..) |sym, i| {211 for (opts.symtab, 0..) |sym, i| {
203 const hidden = self.versyms.items[i] & elf.VERSYM_HIDDEN != 0;212 const hidden = self.versyms.items[i] & elf.VERSYM_HIDDEN != 0;
...@@ -210,45 +219,57 @@ fn initSymtab(self: *SharedObject, elf_file: *Elf, opts: struct {...@@ -210,45 +219,57 @@ fn initSymtab(self: *SharedObject, elf_file: *Elf, opts: struct {
210 self.versionString(self.versyms.items[i]),219 self.versionString(self.versyms.items[i]),
211 });220 });
212 defer gpa.free(mangled);221 defer gpa.free(mangled);
213 const name_off = @as(u32, @intCast(self.strtab.items.len));222 break :blk try self.addString(gpa, mangled);
214 try self.strtab.writer(gpa).print("{s}\x00", .{mangled});
215 break :blk name_off;
216 } else sym.st_name;223 } else sym.st_name;
217 const out_sym = self.symtab.addOneAssumeCapacity();224 const out_esym_index: u32 = @intCast(self.symtab.items.len);
218 out_sym.* = sym;225 const out_esym = self.symtab.addOneAssumeCapacity();
219 out_sym.st_name = name_off;226 out_esym.* = sym;
220 const gop = try elf_file.getOrPutGlobal(self.getString(name_off));227 out_esym.st_name = name_off;
221 self.symbols.addOneAssumeCapacity().* = gop.index;228 const out_sym_index = self.addSymbolAssumeCapacity();
229 const out_sym = &self.symbols.items[out_sym_index];
230 out_sym.value = @intCast(out_esym.st_value);
231 out_sym.name_offset = name_off;
232 out_sym.ref = .{ .index = 0, .file = 0 };
233 out_sym.esym_index = out_esym_index;
234 out_sym.version_index = self.versyms.items[out_esym_index];
235 out_sym.extra_index = self.addSymbolExtraAssumeCapacity(.{});
222 }236 }
223}237}
224238
225pub fn resolveSymbols(self: *SharedObject, elf_file: *Elf) void {239pub fn resolveSymbols(self: *SharedObject, elf_file: *Elf) !void {
226 for (self.globals(), 0..) |index, i| {240 const gpa = elf_file.base.comp.gpa;
227 const esym_index = @as(u32, @intCast(i));241
228 const this_sym = self.symtab.items[esym_index];242 for (self.symtab.items, self.symbols_resolver.items, 0..) |esym, *resolv, i| {
243 const gop = try elf_file.resolver.getOrPut(gpa, .{
244 .index = @intCast(i),
245 .file = self.index,
246 }, elf_file);
247 if (!gop.found_existing) {
248 gop.ref.* = .{ .index = 0, .file = 0 };
249 }
250 resolv.* = gop.index;
229251
230 if (this_sym.st_shndx == elf.SHN_UNDEF) continue;252 if (esym.st_shndx == elf.SHN_UNDEF) continue;
253 if (elf_file.symbol(gop.ref.*) == null) {
254 gop.ref.* = .{ .index = @intCast(i), .file = self.index };
255 continue;
256 }
231257
232 const global = elf_file.symbol(index);258 if (self.asFile().symbolRank(esym, false) < elf_file.symbol(gop.ref.*).?.symbolRank(elf_file)) {
233 if (self.asFile().symbolRank(this_sym, false) < global.symbolRank(elf_file)) {259 gop.ref.* = .{ .index = @intCast(i), .file = self.index };
234 global.value = @intCast(this_sym.st_value);
235 global.ref = .{ .index = 0, .file = 0 };
236 global.esym_index = esym_index;
237 global.version_index = self.versyms.items[esym_index];
238 global.file_index = self.index;
239 }260 }
240 }261 }
241}262}
242263
243pub fn markLive(self: *SharedObject, elf_file: *Elf) void {264pub fn markLive(self: *SharedObject, elf_file: *Elf) void {
244 for (self.globals(), 0..) |index, i| {265 for (self.symtab.items, 0..) |esym, i| {
245 const sym = self.symtab.items[i];266 if (esym.st_shndx != elf.SHN_UNDEF) continue;
246 if (sym.st_shndx != elf.SHN_UNDEF) continue;
247267
248 const global = elf_file.symbol(index);268 const ref = self.resolveSymbol(@intCast(i), elf_file);
249 const file = global.file(elf_file) orelse continue;269 const sym = elf_file.symbol(ref) orelse continue;
270 const file = sym.file(elf_file).?;
250 const should_drop = switch (file) {271 const should_drop = switch (file) {
251 .shared_object => |sh| !sh.needed and sym.st_bind() == elf.STB_WEAK,272 .shared_object => |sh| !sh.needed and esym.st_bind() == elf.STB_WEAK,
252 else => false,273 else => false,
253 };274 };
254 if (!should_drop and !file.isAlive()) {275 if (!should_drop and !file.isAlive()) {
...@@ -258,28 +279,34 @@ pub fn markLive(self: *SharedObject, elf_file: *Elf) void {...@@ -258,28 +279,34 @@ pub fn markLive(self: *SharedObject, elf_file: *Elf) void {
258 }279 }
259}280}
260281
261pub fn globals(self: SharedObject) []const Symbol.Index {282pub fn markImportExports(self: *SharedObject, elf_file: *Elf) void {
262 return self.symbols.items;283 for (0..self.symbols.items.len) |i| {
284 const ref = self.resolveSymbol(@intCast(i), elf_file);
285 const ref_sym = elf_file.symbol(ref) orelse continue;
286 const ref_file = ref_sym.file(elf_file).?;
287 const vis = @as(elf.STV, @enumFromInt(ref_sym.elfSym(elf_file).st_other));
288 if (ref_file != .shared_object and vis != .HIDDEN) ref_sym.flags.@"export" = true;
289 }
263}290}
264291
265pub fn updateSymtabSize(self: *SharedObject, elf_file: *Elf) !void {292pub fn updateSymtabSize(self: *SharedObject, elf_file: *Elf) void {
266 for (self.globals()) |global_index| {293 for (self.symbols.items, self.symbols_resolver.items) |*global, resolv| {
267 const global = elf_file.symbol(global_index);294 const ref = elf_file.resolver.get(resolv).?;
268 const file_ptr = global.file(elf_file) orelse continue;295 const ref_sym = elf_file.symbol(ref) orelse continue;
269 if (file_ptr.index() != self.index) continue;296 if (ref_sym.file(elf_file).?.index() != self.index) continue;
270 if (global.isLocal(elf_file)) continue;297 if (global.isLocal(elf_file)) continue;
271 global.flags.output_symtab = true;298 global.flags.output_symtab = true;
272 try global.addExtra(.{ .symtab = self.output_symtab_ctx.nglobals }, elf_file);299 global.addExtra(.{ .symtab = self.output_symtab_ctx.nglobals }, elf_file);
273 self.output_symtab_ctx.nglobals += 1;300 self.output_symtab_ctx.nglobals += 1;
274 self.output_symtab_ctx.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1;301 self.output_symtab_ctx.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1;
275 }302 }
276}303}
277304
278pub fn writeSymtab(self: SharedObject, elf_file: *Elf) void {305pub fn writeSymtab(self: *SharedObject, elf_file: *Elf) void {
279 for (self.globals()) |global_index| {306 for (self.symbols.items, self.symbols_resolver.items) |global, resolv| {
280 const global = elf_file.symbol(global_index);307 const ref = elf_file.resolver.get(resolv).?;
281 const file_ptr = global.file(elf_file) orelse continue;308 const ref_sym = elf_file.symbol(ref) orelse continue;
282 if (file_ptr.index() != self.index) continue;309 if (ref_sym.file(elf_file).?.index() != self.index) continue;
283 const idx = global.outputSymtabIndex(elf_file) orelse continue;310 const idx = global.outputSymtabIndex(elf_file) orelse continue;
284 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));311 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
285 elf_file.strtab.appendSliceAssumeCapacity(global.name(elf_file));312 elf_file.strtab.appendSliceAssumeCapacity(global.name(elf_file));
...@@ -319,9 +346,12 @@ pub fn initSymbolAliases(self: *SharedObject, elf_file: *Elf) !void {...@@ -319,9 +346,12 @@ pub fn initSymbolAliases(self: *SharedObject, elf_file: *Elf) !void {
319 assert(self.aliases == null);346 assert(self.aliases == null);
320347
321 const SortAlias = struct {348 const SortAlias = struct {
322 pub fn lessThan(ctx: *Elf, lhs: Symbol.Index, rhs: Symbol.Index) bool {349 so: *SharedObject,
323 const lhs_sym = ctx.symbol(lhs).elfSym(ctx);350 ef: *Elf,
324 const rhs_sym = ctx.symbol(rhs).elfSym(ctx);351
352 pub fn lessThan(ctx: @This(), lhs: Symbol.Index, rhs: Symbol.Index) bool {
353 const lhs_sym = ctx.so.symbols.items[lhs].elfSym(ctx.ef);
354 const rhs_sym = ctx.so.symbols.items[rhs].elfSym(ctx.ef);
325 return lhs_sym.st_value < rhs_sym.st_value;355 return lhs_sym.st_value < rhs_sym.st_value;
326 }356 }
327 };357 };
...@@ -330,16 +360,16 @@ pub fn initSymbolAliases(self: *SharedObject, elf_file: *Elf) !void {...@@ -330,16 +360,16 @@ pub fn initSymbolAliases(self: *SharedObject, elf_file: *Elf) !void {
330 const gpa = comp.gpa;360 const gpa = comp.gpa;
331 var aliases = std.ArrayList(Symbol.Index).init(gpa);361 var aliases = std.ArrayList(Symbol.Index).init(gpa);
332 defer aliases.deinit();362 defer aliases.deinit();
333 try aliases.ensureTotalCapacityPrecise(self.globals().len);363 try aliases.ensureTotalCapacityPrecise(self.symbols.items.len);
334364
335 for (self.globals()) |index| {365 for (self.symbols_resolver.items, 0..) |resolv, index| {
336 const global = elf_file.symbol(index);366 const ref = elf_file.resolver.get(resolv).?;
337 const global_file = global.file(elf_file) orelse continue;367 const ref_sym = elf_file.symbol(ref) orelse continue;
338 if (global_file.index() != self.index) continue;368 if (ref_sym.file(elf_file).?.index() != self.index) continue;
339 aliases.appendAssumeCapacity(index);369 aliases.appendAssumeCapacity(@intCast(index));
340 }370 }
341371
342 std.mem.sort(u32, aliases.items, elf_file, SortAlias.lessThan);372 std.mem.sort(u32, aliases.items, SortAlias{ .so = self, .ef = elf_file }, SortAlias.lessThan);
343373
344 self.aliases = aliases.moveToUnmanaged();374 self.aliases = aliases.moveToUnmanaged();
345}375}
...@@ -347,27 +377,93 @@ pub fn initSymbolAliases(self: *SharedObject, elf_file: *Elf) !void {...@@ -347,27 +377,93 @@ pub fn initSymbolAliases(self: *SharedObject, elf_file: *Elf) !void {
347pub fn symbolAliases(self: *SharedObject, index: u32, elf_file: *Elf) []const u32 {377pub fn symbolAliases(self: *SharedObject, index: u32, elf_file: *Elf) []const u32 {
348 assert(self.aliases != null);378 assert(self.aliases != null);
349379
350 const symbol = elf_file.symbol(index).elfSym(elf_file);380 const symbol = self.symbols.items[index].elfSym(elf_file);
351 const aliases = self.aliases.?;381 const aliases = self.aliases.?;
352382
353 const start = for (aliases.items, 0..) |alias, i| {383 const start = for (aliases.items, 0..) |alias, i| {
354 const alias_sym = elf_file.symbol(alias).elfSym(elf_file);384 const alias_sym = self.symbols.items[alias].elfSym(elf_file);
355 if (symbol.st_value == alias_sym.st_value) break i;385 if (symbol.st_value == alias_sym.st_value) break i;
356 } else aliases.items.len;386 } else aliases.items.len;
357387
358 const end = for (aliases.items[start..], 0..) |alias, i| {388 const end = for (aliases.items[start..], 0..) |alias, i| {
359 const alias_sym = elf_file.symbol(alias).elfSym(elf_file);389 const alias_sym = self.symbols.items[alias].elfSym(elf_file);
360 if (symbol.st_value < alias_sym.st_value) break i + start;390 if (symbol.st_value < alias_sym.st_value) break i + start;
361 } else aliases.items.len;391 } else aliases.items.len;
362392
363 return aliases.items[start..end];393 return aliases.items[start..end];
364}394}
365395
396fn addString(self: *SharedObject, allocator: Allocator, str: []const u8) !u32 {
397 const off: u32 = @intCast(self.strtab.items.len);
398 try self.strtab.ensureUnusedCapacity(allocator, str.len + 1);
399 self.strtab.appendSliceAssumeCapacity(str);
400 self.strtab.appendAssumeCapacity(0);
401 return off;
402}
403
366pub fn getString(self: SharedObject, off: u32) [:0]const u8 {404pub fn getString(self: SharedObject, off: u32) [:0]const u8 {
367 assert(off < self.strtab.items.len);405 assert(off < self.strtab.items.len);
368 return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0);406 return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0);
369}407}
370408
409pub fn resolveSymbol(self: SharedObject, index: Symbol.Index, elf_file: *Elf) Elf.Ref {
410 const resolv = self.symbols_resolver.items[index];
411 return elf_file.resolver.get(resolv).?;
412}
413
414fn addSymbol(self: *SharedObject, allocator: Allocator) !Symbol.Index {
415 try self.symbols.ensureUnusedCapacity(allocator, 1);
416 return self.addSymbolAssumeCapacity();
417}
418
419fn addSymbolAssumeCapacity(self: *SharedObject) Symbol.Index {
420 const index: Symbol.Index = @intCast(self.symbols.items.len);
421 self.symbols.appendAssumeCapacity(.{ .file_index = self.index });
422 return index;
423}
424
425pub fn addSymbolExtra(self: *SharedObject, allocator: Allocator, extra: Symbol.Extra) !u32 {
426 const fields = @typeInfo(Symbol.Extra).Struct.fields;
427 try self.symbols_extra.ensureUnusedCapacity(allocator, fields.len);
428 return self.addSymbolExtraAssumeCapacity(extra);
429}
430
431pub fn addSymbolExtraAssumeCapacity(self: *SharedObject, extra: Symbol.Extra) u32 {
432 const index = @as(u32, @intCast(self.symbols_extra.items.len));
433 const fields = @typeInfo(Symbol.Extra).Struct.fields;
434 inline for (fields) |field| {
435 self.symbols_extra.appendAssumeCapacity(switch (field.type) {
436 u32 => @field(extra, field.name),
437 else => @compileError("bad field type"),
438 });
439 }
440 return index;
441}
442
443pub fn symbolExtra(self: *SharedObject, index: u32) Symbol.Extra {
444 const fields = @typeInfo(Symbol.Extra).Struct.fields;
445 var i: usize = index;
446 var result: Symbol.Extra = undefined;
447 inline for (fields) |field| {
448 @field(result, field.name) = switch (field.type) {
449 u32 => self.symbols_extra.items[i],
450 else => @compileError("bad field type"),
451 };
452 i += 1;
453 }
454 return result;
455}
456
457pub fn setSymbolExtra(self: *SharedObject, index: u32, extra: Symbol.Extra) void {
458 const fields = @typeInfo(Symbol.Extra).Struct.fields;
459 inline for (fields, 0..) |field, i| {
460 self.symbols_extra.items[index + i] = switch (field.type) {
461 u32 => @field(extra, field.name),
462 else => @compileError("bad field type"),
463 };
464 }
465}
466
371pub fn format(467pub fn format(
372 self: SharedObject,468 self: SharedObject,
373 comptime unused_fmt_string: []const u8,469 comptime unused_fmt_string: []const u8,
...@@ -402,10 +498,15 @@ fn formatSymtab(...@@ -402,10 +498,15 @@ fn formatSymtab(
402 _ = unused_fmt_string;498 _ = unused_fmt_string;
403 _ = options;499 _ = options;
404 const shared = ctx.shared;500 const shared = ctx.shared;
501 const elf_file = ctx.elf_file;
405 try writer.writeAll(" globals\n");502 try writer.writeAll(" globals\n");
406 for (shared.symbols.items) |index| {503 for (shared.symbols.items, 0..) |sym, i| {
407 const global = ctx.elf_file.symbol(index);504 const ref = shared.resolveSymbol(@intCast(i), elf_file);
408 try writer.print(" {}\n", .{global.fmt(ctx.elf_file)});505 if (elf_file.symbol(ref)) |ref_sym| {
506 try writer.print(" {}\n", .{ref_sym.fmt(elf_file)});
507 } else {
508 try writer.print(" {s} : unclaimed\n", .{sym.name(elf_file)});
509 }
409 }510 }
410}511}
411512
src/link/Elf/Symbol.zig+22-30
...@@ -63,9 +63,7 @@ pub fn @"type"(symbol: Symbol, elf_file: *Elf) u4 {...@@ -63,9 +63,7 @@ pub fn @"type"(symbol: Symbol, elf_file: *Elf) u4 {
63}63}
6464
65pub fn name(symbol: Symbol, elf_file: *Elf) [:0]const u8 {65pub fn name(symbol: Symbol, elf_file: *Elf) [:0]const u8 {
66 if (symbol.flags.global) return elf_file.strings.getAssumeExists(symbol.name_offset);66 return switch (symbol.file(elf_file).?) {
67 const file_ptr = symbol.file(elf_file).?;
68 return switch (file_ptr) {
69 inline else => |x| x.getString(symbol.name_offset),67 inline else => |x| x.getString(symbol.name_offset),
70 };68 };
71}69}
...@@ -87,9 +85,8 @@ pub fn file(symbol: Symbol, elf_file: *Elf) ?File {...@@ -87,9 +85,8 @@ pub fn file(symbol: Symbol, elf_file: *Elf) ?File {
87}85}
8886
89pub fn elfSym(symbol: Symbol, elf_file: *Elf) elf.Elf64_Sym {87pub fn elfSym(symbol: Symbol, elf_file: *Elf) elf.Elf64_Sym {
90 const file_ptr = symbol.file(elf_file).?;88 return switch (symbol.file(elf_file).?) {
91 return switch (file_ptr) {89 .zig_object => |x| x.symtab.items(.elf_sym)[symbol.esym_index],
92 .zig_object => |x| x.elfSym(symbol.esym_index).*,
93 inline else => |x| x.symtab.items[symbol.esym_index],90 inline else => |x| x.symtab.items[symbol.esym_index],
94 };91 };
95}92}
...@@ -159,20 +156,20 @@ pub fn outputSymtabIndex(symbol: Symbol, elf_file: *Elf) ?u32 {...@@ -159,20 +156,20 @@ pub fn outputSymtabIndex(symbol: Symbol, elf_file: *Elf) ?u32 {
159 const symtab_ctx = switch (file_ptr) {156 const symtab_ctx = switch (file_ptr) {
160 inline else => |x| x.output_symtab_ctx,157 inline else => |x| x.output_symtab_ctx,
161 };158 };
162 const idx = symbol.extra(elf_file).?.symtab;159 const idx = symbol.extra(elf_file).symtab;
163 return if (symbol.isLocal(elf_file)) idx + symtab_ctx.ilocal else idx + symtab_ctx.iglobal;160 return if (symbol.isLocal(elf_file)) idx + symtab_ctx.ilocal else idx + symtab_ctx.iglobal;
164}161}
165162
166pub fn gotAddress(symbol: Symbol, elf_file: *Elf) i64 {163pub fn gotAddress(symbol: Symbol, elf_file: *Elf) i64 {
167 if (!symbol.flags.has_got) return 0;164 if (!symbol.flags.has_got) return 0;
168 const extras = symbol.extra(elf_file).?;165 const extras = symbol.extra(elf_file);
169 const entry = elf_file.got.entries.items[extras.got];166 const entry = elf_file.got.entries.items[extras.got];
170 return entry.address(elf_file);167 return entry.address(elf_file);
171}168}
172169
173pub fn pltGotAddress(symbol: Symbol, elf_file: *Elf) i64 {170pub fn pltGotAddress(symbol: Symbol, elf_file: *Elf) i64 {
174 if (!(symbol.flags.has_plt and symbol.flags.has_got)) return 0;171 if (!(symbol.flags.has_plt and symbol.flags.has_got)) return 0;
175 const extras = symbol.extra(elf_file).?;172 const extras = symbol.extra(elf_file);
176 const shdr = elf_file.shdrs.items[elf_file.plt_got_section_index.?];173 const shdr = elf_file.shdrs.items[elf_file.plt_got_section_index.?];
177 const cpu_arch = elf_file.getTarget().cpu.arch;174 const cpu_arch = elf_file.getTarget().cpu.arch;
178 return @intCast(shdr.sh_addr + extras.plt_got * PltGotSection.entrySize(cpu_arch));175 return @intCast(shdr.sh_addr + extras.plt_got * PltGotSection.entrySize(cpu_arch));
...@@ -180,7 +177,7 @@ pub fn pltGotAddress(symbol: Symbol, elf_file: *Elf) i64 {...@@ -180,7 +177,7 @@ pub fn pltGotAddress(symbol: Symbol, elf_file: *Elf) i64 {
180177
181pub fn pltAddress(symbol: Symbol, elf_file: *Elf) i64 {178pub fn pltAddress(symbol: Symbol, elf_file: *Elf) i64 {
182 if (!symbol.flags.has_plt) return 0;179 if (!symbol.flags.has_plt) return 0;
183 const extras = symbol.extra(elf_file).?;180 const extras = symbol.extra(elf_file);
184 const shdr = elf_file.shdrs.items[elf_file.plt_section_index.?];181 const shdr = elf_file.shdrs.items[elf_file.plt_section_index.?];
185 const cpu_arch = elf_file.getTarget().cpu.arch;182 const cpu_arch = elf_file.getTarget().cpu.arch;
186 return @intCast(shdr.sh_addr + extras.plt * PltSection.entrySize(cpu_arch) + PltSection.preambleSize(cpu_arch));183 return @intCast(shdr.sh_addr + extras.plt * PltSection.entrySize(cpu_arch) + PltSection.preambleSize(cpu_arch));
...@@ -188,7 +185,7 @@ pub fn pltAddress(symbol: Symbol, elf_file: *Elf) i64 {...@@ -188,7 +185,7 @@ pub fn pltAddress(symbol: Symbol, elf_file: *Elf) i64 {
188185
189pub fn gotPltAddress(symbol: Symbol, elf_file: *Elf) i64 {186pub fn gotPltAddress(symbol: Symbol, elf_file: *Elf) i64 {
190 if (!symbol.flags.has_plt) return 0;187 if (!symbol.flags.has_plt) return 0;
191 const extras = symbol.extra(elf_file).?;188 const extras = symbol.extra(elf_file);
192 const shdr = elf_file.shdrs.items[elf_file.got_plt_section_index.?];189 const shdr = elf_file.shdrs.items[elf_file.got_plt_section_index.?];
193 return @intCast(shdr.sh_addr + extras.plt * 8 + GotPltSection.preamble_size);190 return @intCast(shdr.sh_addr + extras.plt * 8 + GotPltSection.preamble_size);
194}191}
...@@ -201,21 +198,21 @@ pub fn copyRelAddress(symbol: Symbol, elf_file: *Elf) i64 {...@@ -201,21 +198,21 @@ pub fn copyRelAddress(symbol: Symbol, elf_file: *Elf) i64 {
201198
202pub fn tlsGdAddress(symbol: Symbol, elf_file: *Elf) i64 {199pub fn tlsGdAddress(symbol: Symbol, elf_file: *Elf) i64 {
203 if (!symbol.flags.has_tlsgd) return 0;200 if (!symbol.flags.has_tlsgd) return 0;
204 const extras = symbol.extra(elf_file).?;201 const extras = symbol.extra(elf_file);
205 const entry = elf_file.got.entries.items[extras.tlsgd];202 const entry = elf_file.got.entries.items[extras.tlsgd];
206 return entry.address(elf_file);203 return entry.address(elf_file);
207}204}
208205
209pub fn gotTpAddress(symbol: Symbol, elf_file: *Elf) i64 {206pub fn gotTpAddress(symbol: Symbol, elf_file: *Elf) i64 {
210 if (!symbol.flags.has_gottp) return 0;207 if (!symbol.flags.has_gottp) return 0;
211 const extras = symbol.extra(elf_file).?;208 const extras = symbol.extra(elf_file);
212 const entry = elf_file.got.entries.items[extras.gottp];209 const entry = elf_file.got.entries.items[extras.gottp];
213 return entry.address(elf_file);210 return entry.address(elf_file);
214}211}
215212
216pub fn tlsDescAddress(symbol: Symbol, elf_file: *Elf) i64 {213pub fn tlsDescAddress(symbol: Symbol, elf_file: *Elf) i64 {
217 if (!symbol.flags.has_tlsdesc) return 0;214 if (!symbol.flags.has_tlsdesc) return 0;
218 const extras = symbol.extra(elf_file).?;215 const extras = symbol.extra(elf_file);
219 const entry = elf_file.got.entries.items[extras.tlsdesc];216 const entry = elf_file.got.entries.items[extras.tlsdesc];
220 return entry.address(elf_file);217 return entry.address(elf_file);
221}218}
...@@ -228,14 +225,14 @@ const GetOrCreateZigGotEntryResult = struct {...@@ -228,14 +225,14 @@ const GetOrCreateZigGotEntryResult = struct {
228pub fn getOrCreateZigGotEntry(symbol: *Symbol, symbol_index: Index, elf_file: *Elf) !GetOrCreateZigGotEntryResult {225pub fn getOrCreateZigGotEntry(symbol: *Symbol, symbol_index: Index, elf_file: *Elf) !GetOrCreateZigGotEntryResult {
229 assert(!elf_file.base.isRelocatable());226 assert(!elf_file.base.isRelocatable());
230 assert(symbol.flags.needs_zig_got);227 assert(symbol.flags.needs_zig_got);
231 if (symbol.flags.has_zig_got) return .{ .found_existing = true, .index = symbol.extra(elf_file).?.zig_got };228 if (symbol.flags.has_zig_got) return .{ .found_existing = true, .index = symbol.extra(elf_file).zig_got };
232 const index = try elf_file.zig_got.addSymbol(symbol_index, elf_file);229 const index = try elf_file.zig_got.addSymbol(symbol_index, elf_file);
233 return .{ .found_existing = false, .index = index };230 return .{ .found_existing = false, .index = index };
234}231}
235232
236pub fn zigGotAddress(symbol: Symbol, elf_file: *Elf) i64 {233pub fn zigGotAddress(symbol: Symbol, elf_file: *Elf) i64 {
237 if (!symbol.flags.has_zig_got) return 0;234 if (!symbol.flags.has_zig_got) return 0;
238 const extras = symbol.extra(elf_file).?;235 const extras = symbol.extra(elf_file);
239 return elf_file.zig_got.entryAddress(extras.zig_got, elf_file);236 return elf_file.zig_got.entryAddress(extras.zig_got, elf_file);
240}237}
241238
...@@ -265,11 +262,8 @@ const AddExtraOpts = struct {...@@ -265,11 +262,8 @@ const AddExtraOpts = struct {
265 zig_got: ?u32 = null,262 zig_got: ?u32 = null,
266};263};
267264
268pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, elf_file: *Elf) !void {265pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, elf_file: *Elf) void {
269 if (symbol.extra(elf_file) == null) {266 var extras = symbol.extra(elf_file);
270 symbol.extra_index = try elf_file.addSymbolExtra(.{});
271 }
272 var extras = symbol.extra(elf_file).?;
273 inline for (@typeInfo(@TypeOf(opts)).Struct.fields) |field| {267 inline for (@typeInfo(@TypeOf(opts)).Struct.fields) |field| {
274 if (@field(opts, field.name)) |x| {268 if (@field(opts, field.name)) |x| {
275 @field(extras, field.name) = x;269 @field(extras, field.name) = x;
...@@ -278,12 +272,16 @@ pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, elf_file: *Elf) !void {...@@ -278,12 +272,16 @@ pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, elf_file: *Elf) !void {
278 symbol.setExtra(extras, elf_file);272 symbol.setExtra(extras, elf_file);
279}273}
280274
281pub fn extra(symbol: Symbol, elf_file: *Elf) ?Extra {275pub fn extra(symbol: Symbol, elf_file: *Elf) Extra {
282 return elf_file.symbolExtra(symbol.extra_index);276 return switch (symbol.file(elf_file).?) {
277 inline else => |x| x.symbolExtra(symbol.extra_index),
278 };
283}279}
284280
285pub fn setExtra(symbol: Symbol, extras: Extra, elf_file: *Elf) void {281pub fn setExtra(symbol: Symbol, extras: Extra, elf_file: *Elf) void {
286 elf_file.setSymbolExtra(symbol.extra_index, extras);282 return switch (symbol.file(elf_file).?) {
283 inline else => |x| x.setSymbolExtra(symbol.extra_index, extras),
284 };
287}285}
288286
289pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {287pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {
...@@ -426,12 +424,6 @@ pub const Flags = packed struct {...@@ -426,12 +424,6 @@ pub const Flags = packed struct {
426 /// Whether this symbol is weak.424 /// Whether this symbol is weak.
427 weak: bool = false,425 weak: bool = false,
428426
429 /// Whether the symbol has its name interned in global symbol
430 /// resolver table.
431 /// This happens for any symbol that is considered a global
432 /// symbol, but is not necessarily an import or export.
433 global: bool = false,
434
435 /// Whether the symbol makes into the output symtab.427 /// Whether the symbol makes into the output symtab.
436 output_symtab: bool = false,428 output_symtab: bool = false,
437429
src/link/Elf/ZigObject.zig+309-223
...@@ -8,9 +8,11 @@ data: std.ArrayListUnmanaged(u8) = .{},...@@ -8,9 +8,11 @@ data: std.ArrayListUnmanaged(u8) = .{},
8path: []const u8,8path: []const u8,
9index: File.Index,9index: File.Index,
1010
11local_esyms: std.MultiArrayList(ElfSym) = .{},11symtab: std.MultiArrayList(ElfSym) = .{},
12global_esyms: std.MultiArrayList(ElfSym) = .{},
13strtab: StringTable = .{},12strtab: StringTable = .{},
13symbols: std.ArrayListUnmanaged(Symbol) = .{},
14symbols_extra: std.ArrayListUnmanaged(u32) = .{},
15symbols_resolver: std.ArrayListUnmanaged(Elf.SymbolResolver.Index) = .{},
14local_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},16local_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
15global_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},17global_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
16globals_lookup: std.AutoHashMapUnmanaged(u32, Symbol.Index) = .{},18globals_lookup: std.AutoHashMapUnmanaged(u32, Symbol.Index) = .{},
...@@ -87,18 +89,11 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void {...@@ -87,18 +89,11 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void {
87 try self.strtab.buffer.append(gpa, 0);89 try self.strtab.buffer.append(gpa, 0);
8890
89 const name_off = try self.strtab.insert(gpa, self.path);91 const name_off = try self.strtab.insert(gpa, self.path);
90 const symbol_index = try elf_file.addSymbol();92 const symbol_index = try self.newLocalSymbol(gpa, name_off);
91 try self.local_symbols.append(gpa, symbol_index);93 const sym = self.symbol(symbol_index);
92 const symbol_ptr = elf_file.symbol(symbol_index);94 const esym = &self.symtab.items(.elf_sym)[sym.esym_index];
93 symbol_ptr.file_index = self.index;
94 symbol_ptr.name_offset = name_off;
95
96 const esym_index = try self.addLocalEsym(gpa);
97 const esym = &self.local_esyms.items(.elf_sym)[esym_index];
98 esym.st_name = name_off;
99 esym.st_info = elf.STT_FILE;95 esym.st_info = elf.STT_FILE;
100 esym.st_shndx = elf.SHN_ABS;96 esym.st_shndx = elf.SHN_ABS;
101 symbol_ptr.esym_index = esym_index;
10297
103 switch (comp.config.debug_format) {98 switch (comp.config.debug_format) {
104 .strip => {},99 .strip => {},
...@@ -112,9 +107,11 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void {...@@ -112,9 +107,11 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void {
112107
113pub fn deinit(self: *ZigObject, allocator: Allocator) void {108pub fn deinit(self: *ZigObject, allocator: Allocator) void {
114 self.data.deinit(allocator);109 self.data.deinit(allocator);
115 self.local_esyms.deinit(allocator);110 self.symtab.deinit(allocator);
116 self.global_esyms.deinit(allocator);
117 self.strtab.deinit(allocator);111 self.strtab.deinit(allocator);
112 self.symbols.deinit(allocator);
113 self.symbols_extra.deinit(allocator);
114 self.symbols_resolver.deinit(allocator);
118 self.local_symbols.deinit(allocator);115 self.local_symbols.deinit(allocator);
119 self.global_symbols.deinit(allocator);116 self.global_symbols.deinit(allocator);
120 self.globals_lookup.deinit(allocator);117 self.globals_lookup.deinit(allocator);
...@@ -262,50 +259,75 @@ fn saveDebugSectionsSizes(self: *ZigObject, elf_file: *Elf) void {...@@ -262,50 +259,75 @@ fn saveDebugSectionsSizes(self: *ZigObject, elf_file: *Elf) void {
262 }259 }
263}260}
264261
265pub fn addLocalEsym(self: *ZigObject, allocator: Allocator) !Symbol.Index {262fn newSymbol(self: *ZigObject, allocator: Allocator, name_off: u32, st_bind: u4) !Symbol.Index {
266 try self.local_esyms.ensureUnusedCapacity(allocator, 1);263 try self.symtab.ensureUnusedCapacity(allocator, 1);
267 const index = @as(Symbol.Index, @intCast(self.local_esyms.addOneAssumeCapacity()));264 try self.symbols.ensureUnusedCapacity(allocator, 1);
268 var esym = ElfSym{ .elf_sym = Elf.null_sym };265 try self.symbols_extra.ensureUnusedCapacity(allocator, @sizeOf(Symbol.Extra));
269 esym.elf_sym.st_info = elf.STB_LOCAL << 4;266
270 self.local_esyms.set(index, esym);267 const index = self.addSymbolAssumeCapacity();
268 const sym = &self.symbols.items[index];
269 sym.name_offset = name_off;
270 sym.extra_index = self.addSymbolExtraAssumeCapacity(.{});
271
272 const esym_idx: u32 = @intCast(self.symtab.addOneAssumeCapacity());
273 const esym = ElfSym{ .elf_sym = .{
274 .st_value = 0,
275 .st_name = name_off,
276 .st_info = @as(u8, @intCast(st_bind)) << 4,
277 .st_other = 0,
278 .st_size = 0,
279 .st_shndx = 0,
280 } };
281 self.symtab.set(index, esym);
282 sym.esym_index = esym_idx;
283
271 return index;284 return index;
272}285}
273286
274pub fn addGlobalEsym(self: *ZigObject, allocator: Allocator) !Symbol.Index {287fn newLocalSymbol(self: *ZigObject, allocator: Allocator, name_off: u32) !Symbol.Index {
275 try self.global_esyms.ensureUnusedCapacity(allocator, 1);288 try self.local_symbols.ensureUnusedCapacity(allocator, 1);
276 const index = @as(Symbol.Index, @intCast(self.global_esyms.addOneAssumeCapacity()));289 const fake_index: Symbol.Index = @intCast(self.local_symbols.items.len);
277 var esym = ElfSym{ .elf_sym = Elf.null_sym };290 const index = try self.newSymbol(allocator, name_off, elf.STB_LOCAL);
278 esym.elf_sym.st_info = elf.STB_GLOBAL << 4;291 self.local_symbols.appendAssumeCapacity(index);
279 self.global_esyms.set(index, esym);292 return fake_index;
280 return index | global_symbol_bit;
281}293}
282294
283pub fn newAtom(self: *ZigObject, elf_file: *Elf) !Symbol.Index {295fn newGlobalSymbol(self: *ZigObject, allocator: Allocator, name_off: u32) !Symbol.Index {
284 const gpa = elf_file.base.comp.gpa;296 try self.global_symbols.ensureUnusedCapacity(allocator, 1);
285 const atom_index = try self.addAtom(gpa);297 try self.symbols_resolver.ensureUnusedCapacity(allocator, 1);
286 const symbol_index = try elf_file.addSymbol();298 const fake_index: Symbol.Index = @intCast(self.global_symbols.items.len);
287 const esym_index = try self.addLocalEsym(gpa);299 const index = try self.newSymbol(allocator, name_off, elf.STB_GLOBAL);
288300 self.global_symbols.appendAssumeCapacity(index);
289 try self.atoms_indexes.append(gpa, atom_index);301 self.symbols_resolver.addOneAssumeCapacity().* = 0;
290 try self.local_symbols.append(gpa, symbol_index);302 return fake_index | global_symbol_bit;
291303}
292 const symbol_ptr = elf_file.symbol(symbol_index);
293 symbol_ptr.file_index = self.index;
294 symbol_ptr.ref = .{ .index = atom_index, .file = self.index };
295304
296 self.local_esyms.items(.shndx)[esym_index] = atom_index;305fn newAtom(self: *ZigObject, allocator: Allocator, name_off: u32) !Atom.Index {
297 self.local_esyms.items(.elf_sym)[esym_index].st_shndx = SHN_ATOM;306 try self.atoms.ensureUnusedCapacity(allocator, 1);
298 symbol_ptr.esym_index = esym_index;307 try self.atoms_extra.ensureUnusedCapacity(allocator, @sizeOf(Atom.Extra));
308 try self.atoms_indexes.ensureUnusedCapacity(allocator, 1);
309 try self.relocs.ensureUnusedCapacity(allocator, 1);
299310
300 // TODO I'm thinking that maybe we shouldn' set this value unless it's actually needed?311 const index = self.addAtomAssumeCapacity();
301 const relocs_index = @as(u32, @intCast(self.relocs.items.len));312 self.atoms_indexes.appendAssumeCapacity(index);
302 const relocs = try self.relocs.addOne(gpa);313 const atom_ptr = self.atom(index).?;
303 relocs.* = .{};314 atom_ptr.name_offset = name_off;
304315
305 const atom_ptr = self.atom(atom_index).?;316 const relocs_index: u32 = @intCast(self.relocs.items.len);
317 self.relocs.addOneAssumeCapacity().* = .{};
306 atom_ptr.relocs_section_index = relocs_index;318 atom_ptr.relocs_section_index = relocs_index;
307319
308 return symbol_index;320 return index;
321}
322
323fn newSymbolWithAtom(self: *ZigObject, allocator: Allocator, name_off: u32) !Symbol.Index {
324 const atom_index = try self.newAtom(allocator, name_off);
325 const sym_index = try self.newLocalSymbol(allocator, name_off);
326 const sym = self.symbol(sym_index);
327 sym.ref = .{ .index = atom_index, .file = self.index };
328 self.symtab.items(.shndx)[sym.esym_index] = atom_index;
329 self.symtab.items(.elf_sym)[sym.esym_index].st_shndx = SHN_ATOM;
330 return sym_index;
309}331}
310332
311/// TODO actually create fake input shdrs and return that instead.333/// TODO actually create fake input shdrs and return that instead.
...@@ -320,48 +342,47 @@ pub fn inputShdr(self: *ZigObject, atom_index: Atom.Index, elf_file: *Elf) elf.E...@@ -320,48 +342,47 @@ pub fn inputShdr(self: *ZigObject, atom_index: Atom.Index, elf_file: *Elf) elf.E
320 return shdr;342 return shdr;
321}343}
322344
323pub fn resolveSymbols(self: *ZigObject, elf_file: *Elf) void {345pub fn resolveSymbols(self: *ZigObject, elf_file: *Elf) !void {
324 for (self.globals(), 0..) |index, i| {346 const gpa = elf_file.base.comp.gpa;
325 const esym_index = @as(Symbol.Index, @intCast(i)) | global_symbol_bit;
326 const esym = self.global_esyms.items(.elf_sym)[i];
327 const shndx = self.global_esyms.items(.shndx)[i];
328
329 if (esym.st_shndx == elf.SHN_UNDEF) continue;
330347
331 if (esym.st_shndx != elf.SHN_ABS and esym.st_shndx != elf.SHN_COMMON) {348 for (self.global_symbols.items, 0..) |index, i| {
349 const global = &self.symbols.items[index];
350 const esym = global.elfSym(elf_file);
351 const shndx = self.symtab.items(.shndx)[global.esym_index];
352 if (esym.st_shndx != elf.SHN_ABS and esym.st_shndx != elf.SHN_COMMON and esym.st_shndx != elf.SHN_UNDEF) {
332 assert(esym.st_shndx == SHN_ATOM);353 assert(esym.st_shndx == SHN_ATOM);
333 const atom_ptr = self.atom(shndx) orelse continue;354 const atom_ptr = self.atom(shndx) orelse continue;
334 if (!atom_ptr.alive) continue;355 if (!atom_ptr.alive) continue;
335 }356 }
336357
337 const global = elf_file.symbol(index);358 const resolv = &self.symbols_resolver.items[i];
338 if (self.asFile().symbolRank(esym, false) < global.symbolRank(elf_file)) {359 const gop = try elf_file.resolver.getOrPut(gpa, .{
339 const atom_index = switch (esym.st_shndx) {360 .index = @intCast(i | global_symbol_bit),
340 elf.SHN_ABS, elf.SHN_COMMON => 0,361 .file = self.index,
341 SHN_ATOM => shndx,362 }, elf_file);
342 else => unreachable,363 if (!gop.found_existing) {
343 };364 gop.ref.* = .{ .index = 0, .file = 0 };
344 global.value = @intCast(esym.st_value);365 }
345 global.ref = .{ .index = atom_index, .file = self.index };366 resolv.* = gop.index;
346 global.esym_index = esym_index;367
347 global.file_index = self.index;368 if (esym.st_shndx == elf.SHN_UNDEF) continue;
348 global.version_index = elf_file.default_sym_version;369 if (elf_file.symbol(gop.ref.*) == null) {
349 if (esym.st_bind() == elf.STB_WEAK) global.flags.weak = true;370 gop.ref.* = .{ .index = @intCast(i | global_symbol_bit), .file = self.index };
371 continue;
372 }
373
374 if (self.asFile().symbolRank(esym, false) < elf_file.symbol(gop.ref.*).?.symbolRank(elf_file)) {
375 gop.ref.* = .{ .index = @intCast(i | global_symbol_bit), .file = self.index };
350 }376 }
351 }377 }
352}378}
353379
354pub fn claimUnresolved(self: ZigObject, elf_file: *Elf) void {380pub fn claimUnresolved(self: *ZigObject, elf_file: *Elf) void {
355 for (self.globals(), 0..) |index, i| {381 for (self.global_symbols.items, 0..) |index, i| {
356 const esym_index = @as(Symbol.Index, @intCast(i)) | global_symbol_bit;382 const global = &self.symbols.items[index];
357 const esym = self.global_esyms.items(.elf_sym)[i];383 const esym = self.symtab.items(.elf_sym)[index];
358
359 if (esym.st_shndx != elf.SHN_UNDEF) continue;384 if (esym.st_shndx != elf.SHN_UNDEF) continue;
360385 if (elf_file.symbol(self.resolveSymbol(@intCast(i | global_symbol_bit), elf_file)) != null) continue;
361 const global = elf_file.symbol(index);
362 if (global.file(elf_file)) |_| {
363 if (global.elfSym(elf_file).st_shndx != elf.SHN_UNDEF) continue;
364 }
365386
366 const is_import = blk: {387 const is_import = blk: {
367 if (!elf_file.isEffectivelyDynLib()) break :blk false;388 if (!elf_file.isEffectivelyDynLib()) break :blk false;
...@@ -372,29 +393,30 @@ pub fn claimUnresolved(self: ZigObject, elf_file: *Elf) void {...@@ -372,29 +393,30 @@ pub fn claimUnresolved(self: ZigObject, elf_file: *Elf) void {
372393
373 global.value = 0;394 global.value = 0;
374 global.ref = .{ .index = 0, .file = 0 };395 global.ref = .{ .index = 0, .file = 0 };
375 global.esym_index = esym_index;396 global.esym_index = @intCast(index);
376 global.file_index = self.index;397 global.file_index = self.index;
377 global.version_index = if (is_import) elf.VER_NDX_LOCAL else elf_file.default_sym_version;398 global.version_index = if (is_import) elf.VER_NDX_LOCAL else elf_file.default_sym_version;
378 global.flags.import = is_import;399 global.flags.import = is_import;
400
401 const idx = self.symbols_resolver.items[i];
402 elf_file.resolver.values.items[idx - 1] = .{ .index = @intCast(i | global_symbol_bit), .file = self.index };
379 }403 }
380}404}
381405
382pub fn claimUnresolvedObject(self: ZigObject, elf_file: *Elf) void {406pub fn claimUnresolvedObject(self: ZigObject, elf_file: *Elf) void {
383 for (self.globals(), 0..) |index, i| {407 for (self.global_symbols.items, 0..) |index, i| {
384 const esym_index = @as(Symbol.Index, @intCast(i)) | global_symbol_bit;408 const global = &self.symbols.items[index];
385 const esym = self.global_esyms.items(.elf_sym)[i];409 const esym = self.symtab.items(.elf_sym)[index];
386
387 if (esym.st_shndx != elf.SHN_UNDEF) continue;410 if (esym.st_shndx != elf.SHN_UNDEF) continue;
388411 if (elf_file.symbol(self.resolveSymbol(@intCast(i | global_symbol_bit), elf_file)) != null) continue;
389 const global = elf_file.symbol(index);
390 if (global.file(elf_file)) |file| {
391 if (global.elfSym(elf_file).st_shndx != elf.SHN_UNDEF or file.index() <= self.index) continue;
392 }
393412
394 global.value = 0;413 global.value = 0;
395 global.ref = .{ .index = 0, .file = 0 };414 global.ref = .{ .index = 0, .file = 0 };
396 global.esym_index = esym_index;415 global.esym_index = @intCast(index);
397 global.file_index = self.index;416 global.file_index = self.index;
417
418 const idx = self.symbols_resolver.items[i];
419 elf_file.resolver.values.items[idx - 1] = .{ .index = @intCast(i | global_symbol_bit), .file = self.index };
398 }420 }
399}421}
400422
...@@ -417,12 +439,14 @@ pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void {...@@ -417,12 +439,14 @@ pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void {
417}439}
418440
419pub fn markLive(self: *ZigObject, elf_file: *Elf) void {441pub fn markLive(self: *ZigObject, elf_file: *Elf) void {
420 for (self.globals(), 0..) |index, i| {442 for (self.global_symbols.items, 0..) |index, i| {
421 const esym = self.global_esyms.items(.elf_sym)[i];443 const global = self.symbols.items[index];
444 const esym = self.symtab.items(.elf_sym)[index];
422 if (esym.st_bind() == elf.STB_WEAK) continue;445 if (esym.st_bind() == elf.STB_WEAK) continue;
423446
424 const global = elf_file.symbol(index);447 const ref = self.resolveSymbol(@intCast(i | global_symbol_bit), elf_file);
425 const file = global.file(elf_file) orelse continue;448 const sym = elf_file.symbol(ref) orelse continue;
449 const file = sym.file(elf_file).?;
426 const should_keep = esym.st_shndx == elf.SHN_UNDEF or450 const should_keep = esym.st_shndx == elf.SHN_UNDEF or
427 (esym.st_shndx == elf.SHN_COMMON and global.elfSym(elf_file).st_shndx != elf.SHN_COMMON);451 (esym.st_shndx == elf.SHN_COMMON and global.elfSym(elf_file).st_shndx != elf.SHN_COMMON);
428 if (should_keep and !file.isAlive()) {452 if (should_keep and !file.isAlive()) {
...@@ -432,14 +456,36 @@ pub fn markLive(self: *ZigObject, elf_file: *Elf) void {...@@ -432,14 +456,36 @@ pub fn markLive(self: *ZigObject, elf_file: *Elf) void {
432 }456 }
433}457}
434458
435pub fn checkDuplicates(self: *ZigObject, dupes: anytype, elf_file: *Elf) error{OutOfMemory}!void {459pub fn markImportsExports(self: *ZigObject, elf_file: *Elf) void {
436 for (self.globals(), 0..) |index, i| {460 for (0..self.global_symbols.items.len) |i| {
437 const esym = self.global_esyms.items(.elf_sym)[i];461 const ref = self.resolveSymbol(@intCast(i | global_symbol_bit), elf_file);
438 const shndx = self.global_esyms.items(.shndx)[i];462 const sym = elf_file.symbol(ref) orelse continue;
439 const global = elf_file.symbol(index);463 const file = sym.file(elf_file).?;
440 const global_file = global.file(elf_file) orelse continue;464 if (sym.version_index == elf.VER_NDX_LOCAL) continue;
465 const vis = @as(elf.STV, @enumFromInt(sym.elfSym(elf_file).st_other));
466 if (vis == .HIDDEN) continue;
467 if (file == .shared_object and !sym.isAbs(elf_file)) {
468 sym.flags.import = true;
469 continue;
470 }
471 if (file.index() == self.index) {
472 sym.flags.@"export" = true;
473 if (elf_file.isEffectivelyDynLib() and vis != .PROTECTED) {
474 sym.flags.import = true;
475 }
476 }
477 }
478}
441479
442 if (self.index == global_file.index() or480pub fn checkDuplicates(self: *ZigObject, dupes: anytype, elf_file: *Elf) error{OutOfMemory}!void {
481 for (self.global_symbols.items, 0..) |index, i| {
482 const esym = self.symtab.items(.elf_sym)[index];
483 const shndx = self.symtab.items(.shndx)[index];
484 const ref = self.resolveSymbol(@intCast(i | global_symbol_bit), elf_file);
485 const ref_sym = elf_file.symbol(ref) orelse continue;
486 const ref_file = ref_sym.file(elf_file).?;
487
488 if (self.index == ref_file.index() or
443 esym.st_shndx == elf.SHN_UNDEF or489 esym.st_shndx == elf.SHN_UNDEF or
444 esym.st_bind() == elf.STB_WEAK or490 esym.st_bind() == elf.STB_WEAK or
445 esym.st_shndx == elf.SHN_COMMON) continue;491 esym.st_shndx == elf.SHN_COMMON) continue;
...@@ -449,7 +495,7 @@ pub fn checkDuplicates(self: *ZigObject, dupes: anytype, elf_file: *Elf) error{O...@@ -449,7 +495,7 @@ pub fn checkDuplicates(self: *ZigObject, dupes: anytype, elf_file: *Elf) error{O
449 if (!atom_ptr.alive) continue;495 if (!atom_ptr.alive) continue;
450 }496 }
451497
452 const gop = try dupes.getOrPut(index);498 const gop = try dupes.getOrPut(self.symbols_resolver.items[i]);
453 if (!gop.found_existing) {499 if (!gop.found_existing) {
454 gop.value_ptr.* = .{};500 gop.value_ptr.* = .{};
455 }501 }
...@@ -481,12 +527,13 @@ pub fn readFileContents(self: *ZigObject, elf_file: *Elf) !void {...@@ -481,12 +527,13 @@ pub fn readFileContents(self: *ZigObject, elf_file: *Elf) !void {
481pub fn updateArSymtab(self: ZigObject, ar_symtab: *Archive.ArSymtab, elf_file: *Elf) error{OutOfMemory}!void {527pub fn updateArSymtab(self: ZigObject, ar_symtab: *Archive.ArSymtab, elf_file: *Elf) error{OutOfMemory}!void {
482 const gpa = elf_file.base.comp.gpa;528 const gpa = elf_file.base.comp.gpa;
483529
484 try ar_symtab.symtab.ensureUnusedCapacity(gpa, self.globals().len);530 try ar_symtab.symtab.ensureUnusedCapacity(gpa, self.global_symbols.items.len);
485531
486 for (self.globals()) |global_index| {532 for (self.global_symbols.items, 0..) |index, i| {
487 const global = elf_file.symbol(global_index);533 const global = self.symbols.items[index];
488 const file_ptr = global.file(elf_file).?;534 const ref = self.resolveSymbol(@intCast(i | global_symbol_bit), elf_file);
489 assert(file_ptr.index() == self.index);535 const sym = elf_file.symbol(ref).?;
536 assert(sym.file(elf_file).?.index() == self.index);
490 if (global.outputShndx(elf_file) == null) continue;537 if (global.outputShndx(elf_file) == null) continue;
491538
492 const off = try ar_symtab.strtab.insert(gpa, global.name(elf_file));539 const off = try ar_symtab.strtab.insert(gpa, global.name(elf_file));
...@@ -528,33 +575,9 @@ pub fn addAtomsToRelaSections(self: *ZigObject, elf_file: *Elf) !void {...@@ -528,33 +575,9 @@ pub fn addAtomsToRelaSections(self: *ZigObject, elf_file: *Elf) !void {
528 }575 }
529}576}
530577
531inline fn isGlobal(index: Symbol.Index) bool {
532 return index & global_symbol_bit != 0;
533}
534
535pub fn symbol(self: ZigObject, index: Symbol.Index) Symbol.Index {
536 const actual_index = index & symbol_mask;
537 if (isGlobal(index)) return self.globals()[actual_index];
538 return self.locals()[actual_index];
539}
540
541pub fn elfSym(self: *ZigObject, index: Symbol.Index) *elf.Elf64_Sym {
542 const actual_index = index & symbol_mask;
543 if (isGlobal(index)) return &self.global_esyms.items(.elf_sym)[actual_index];
544 return &self.local_esyms.items(.elf_sym)[actual_index];
545}
546
547pub fn locals(self: ZigObject) []const Symbol.Index {
548 return self.local_symbols.items;
549}
550
551pub fn globals(self: ZigObject) []const Symbol.Index {
552 return self.global_symbols.items;
553}
554
555pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) !void {578pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) !void {
556 for (self.locals()) |local_index| {579 for (self.local_symbols.items) |index| {
557 const local = elf_file.symbol(local_index);580 const local = &self.symbols.items[index];
558 if (local.atom(elf_file)) |atom_ptr| if (!atom_ptr.alive) continue;581 if (local.atom(elf_file)) |atom_ptr| if (!atom_ptr.alive) continue;
559 const esym = local.elfSym(elf_file);582 const esym = local.elfSym(elf_file);
560 switch (esym.st_type()) {583 switch (esym.st_type()) {
...@@ -562,22 +585,23 @@ pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) !void {...@@ -562,22 +585,23 @@ pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) !void {
562 else => {},585 else => {},
563 }586 }
564 local.flags.output_symtab = true;587 local.flags.output_symtab = true;
565 try local.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file);588 local.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file);
566 self.output_symtab_ctx.nlocals += 1;589 self.output_symtab_ctx.nlocals += 1;
567 self.output_symtab_ctx.strsize += @as(u32, @intCast(local.name(elf_file).len)) + 1;590 self.output_symtab_ctx.strsize += @as(u32, @intCast(local.name(elf_file).len)) + 1;
568 }591 }
569592
570 for (self.globals()) |global_index| {593 for (self.global_symbols.items, self.symbols_resolver.items) |index, resolv| {
571 const global = elf_file.symbol(global_index);594 const global = &self.symbols.items[index];
572 const file_ptr = global.file(elf_file) orelse continue;595 const ref = elf_file.resolver.values.items[resolv - 1];
573 if (file_ptr.index() != self.index) continue;596 const ref_sym = elf_file.symbol(ref) orelse continue;
597 if (ref_sym.file(elf_file).?.index() != self.index) continue;
574 if (global.atom(elf_file)) |atom_ptr| if (!atom_ptr.alive) continue;598 if (global.atom(elf_file)) |atom_ptr| if (!atom_ptr.alive) continue;
575 global.flags.output_symtab = true;599 global.flags.output_symtab = true;
576 if (global.isLocal(elf_file)) {600 if (global.isLocal(elf_file)) {
577 try global.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file);601 global.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file);
578 self.output_symtab_ctx.nlocals += 1;602 self.output_symtab_ctx.nlocals += 1;
579 } else {603 } else {
580 try global.addExtra(.{ .symtab = self.output_symtab_ctx.nglobals }, elf_file);604 global.addExtra(.{ .symtab = self.output_symtab_ctx.nglobals }, elf_file);
581 self.output_symtab_ctx.nglobals += 1;605 self.output_symtab_ctx.nglobals += 1;
582 }606 }
583 self.output_symtab_ctx.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1;607 self.output_symtab_ctx.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1;
...@@ -585,8 +609,8 @@ pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) !void {...@@ -585,8 +609,8 @@ pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) !void {
585}609}
586610
587pub fn writeSymtab(self: ZigObject, elf_file: *Elf) void {611pub fn writeSymtab(self: ZigObject, elf_file: *Elf) void {
588 for (self.locals()) |local_index| {612 for (self.local_symbols.items) |index| {
589 const local = elf_file.symbol(local_index);613 const local = &self.symbols.items[index];
590 const idx = local.outputSymtabIndex(elf_file) orelse continue;614 const idx = local.outputSymtabIndex(elf_file) orelse continue;
591 const out_sym = &elf_file.symtab.items[idx];615 const out_sym = &elf_file.symtab.items[idx];
592 out_sym.st_name = @intCast(elf_file.strtab.items.len);616 out_sym.st_name = @intCast(elf_file.strtab.items.len);
...@@ -595,10 +619,11 @@ pub fn writeSymtab(self: ZigObject, elf_file: *Elf) void {...@@ -595,10 +619,11 @@ pub fn writeSymtab(self: ZigObject, elf_file: *Elf) void {
595 local.setOutputSym(elf_file, out_sym);619 local.setOutputSym(elf_file, out_sym);
596 }620 }
597621
598 for (self.globals()) |global_index| {622 for (self.global_symbols.items, self.symbols_resolver.items) |index, resolv| {
599 const global = elf_file.symbol(global_index);623 const global = self.symbols.items[index];
600 const file_ptr = global.file(elf_file) orelse continue;624 const ref = elf_file.resolver.values.items[resolv - 1];
601 if (file_ptr.index() != self.index) continue;625 const ref_sym = elf_file.symbol(ref) orelse continue;
626 if (ref_sym.file(elf_file).?.index() != self.index) continue;
602 const idx = global.outputSymtabIndex(elf_file) orelse continue;627 const idx = global.outputSymtabIndex(elf_file) orelse continue;
603 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));628 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
604 elf_file.strtab.appendSliceAssumeCapacity(global.name(elf_file));629 elf_file.strtab.appendSliceAssumeCapacity(global.name(elf_file));
...@@ -609,10 +634,6 @@ pub fn writeSymtab(self: ZigObject, elf_file: *Elf) void {...@@ -609,10 +634,6 @@ pub fn writeSymtab(self: ZigObject, elf_file: *Elf) void {
609 }634 }
610}635}
611636
612pub fn asFile(self: *ZigObject) File {
613 return .{ .zig_object = self };
614}
615
616/// Returns atom's code.637/// Returns atom's code.
617/// Caller owns the memory.638/// Caller owns the memory.
618pub fn codeAlloc(self: *ZigObject, elf_file: *Elf, atom_index: Atom.Index) ![]u8 {639pub fn codeAlloc(self: *ZigObject, elf_file: *Elf, atom_index: Atom.Index) ![]u8 {
...@@ -645,13 +666,13 @@ pub fn getDeclVAddr(...@@ -645,13 +666,13 @@ pub fn getDeclVAddr(
645 reloc_info: link.File.RelocInfo,666 reloc_info: link.File.RelocInfo,
646) !u64 {667) !u64 {
647 const this_sym_index = try self.getOrCreateMetadataForDecl(elf_file, decl_index);668 const this_sym_index = try self.getOrCreateMetadataForDecl(elf_file, decl_index);
648 const this_sym = elf_file.symbol(this_sym_index);669 const this_sym = self.symbol(this_sym_index);
649 const vaddr = this_sym.address(.{}, elf_file);670 const vaddr = this_sym.address(.{}, elf_file);
650 const parent_atom = elf_file.symbol(reloc_info.parent_atom_index).atom(elf_file).?;671 const parent_atom = self.symbol(reloc_info.parent_atom_index).atom(elf_file).?;
651 const r_type = relocation.encode(.abs, elf_file.getTarget().cpu.arch);672 const r_type = relocation.encode(.abs, elf_file.getTarget().cpu.arch);
652 try parent_atom.addReloc(elf_file, .{673 try parent_atom.addReloc(elf_file, .{
653 .r_offset = reloc_info.offset,674 .r_offset = reloc_info.offset,
654 .r_info = (@as(u64, @intCast(this_sym.esym_index)) << 32) | r_type,675 .r_info = (@as(u64, @intCast(this_sym_index)) << 32) | r_type,
655 .r_addend = reloc_info.addend,676 .r_addend = reloc_info.addend,
656 });677 });
657 return @intCast(vaddr);678 return @intCast(vaddr);
...@@ -664,13 +685,13 @@ pub fn getAnonDeclVAddr(...@@ -664,13 +685,13 @@ pub fn getAnonDeclVAddr(
664 reloc_info: link.File.RelocInfo,685 reloc_info: link.File.RelocInfo,
665) !u64 {686) !u64 {
666 const sym_index = self.anon_decls.get(decl_val).?.symbol_index;687 const sym_index = self.anon_decls.get(decl_val).?.symbol_index;
667 const sym = elf_file.symbol(sym_index);688 const sym = self.symbol(sym_index);
668 const vaddr = sym.address(.{}, elf_file);689 const vaddr = sym.address(.{}, elf_file);
669 const parent_atom = elf_file.symbol(reloc_info.parent_atom_index).atom(elf_file).?;690 const parent_atom = self.symbol(reloc_info.parent_atom_index).atom(elf_file).?;
670 const r_type = relocation.encode(.abs, elf_file.getTarget().cpu.arch);691 const r_type = relocation.encode(.abs, elf_file.getTarget().cpu.arch);
671 try parent_atom.addReloc(elf_file, .{692 try parent_atom.addReloc(elf_file, .{
672 .r_offset = reloc_info.offset,693 .r_offset = reloc_info.offset,
673 .r_info = (@as(u64, @intCast(sym.esym_index)) << 32) | r_type,694 .r_info = (@as(u64, @intCast(sym_index)) << 32) | r_type,
674 .r_addend = reloc_info.addend,695 .r_addend = reloc_info.addend,
675 });696 });
676 return @intCast(vaddr);697 return @intCast(vaddr);
...@@ -692,7 +713,7 @@ pub fn lowerAnonDecl(...@@ -692,7 +713,7 @@ pub fn lowerAnonDecl(
692 else => explicit_alignment,713 else => explicit_alignment,
693 };714 };
694 if (self.anon_decls.get(decl_val)) |metadata| {715 if (self.anon_decls.get(decl_val)) |metadata| {
695 const existing_alignment = elf_file.symbol(metadata.symbol_index).atom(elf_file).?.alignment;716 const existing_alignment = self.symbol(metadata.symbol_index).atom(elf_file).?.alignment;
696 if (decl_alignment.order(existing_alignment).compare(.lte))717 if (decl_alignment.order(existing_alignment).compare(.lte))
697 return .ok;718 return .ok;
698 }719 }
...@@ -753,8 +774,8 @@ pub fn getOrCreateMetadataForLazySymbol(...@@ -753,8 +774,8 @@ pub fn getOrCreateMetadataForLazySymbol(
753 };774 };
754 switch (metadata.state.*) {775 switch (metadata.state.*) {
755 .unused => {776 .unused => {
756 const symbol_index = try self.newAtom(elf_file);777 const symbol_index = try self.newSymbolWithAtom(gpa, 0);
757 const sym = elf_file.symbol(symbol_index);778 const sym = self.symbol(symbol_index);
758 sym.flags.needs_zig_got = true;779 sym.flags.needs_zig_got = true;
759 metadata.symbol_index.* = symbol_index;780 metadata.symbol_index.* = symbol_index;
760 },781 },
...@@ -778,13 +799,10 @@ fn freeUnnamedConsts(self: *ZigObject, elf_file: *Elf, decl_index: InternPool.De...@@ -778,13 +799,10 @@ fn freeUnnamedConsts(self: *ZigObject, elf_file: *Elf, decl_index: InternPool.De
778}799}
779800
780fn freeDeclMetadata(self: *ZigObject, elf_file: *Elf, sym_index: Symbol.Index) void {801fn freeDeclMetadata(self: *ZigObject, elf_file: *Elf, sym_index: Symbol.Index) void {
781 _ = self;802 const sym = self.symbol(sym_index);
782 const gpa = elf_file.base.comp.gpa;
783 const sym = elf_file.symbol(sym_index);
784 sym.atom(elf_file).?.free(elf_file);803 sym.atom(elf_file).?.free(elf_file);
785 log.debug("adding %{d} to local symbols free list", .{sym_index});804 log.debug("adding %{d} to local symbols free list", .{sym_index});
786 elf_file.symbols_free_list.append(gpa, sym_index) catch {};805 self.symbols.items[sym_index] = .{};
787 elf_file.symbols.items[sym_index] = .{};
788 // TODO free GOT entry here806 // TODO free GOT entry here
789}807}
790808
...@@ -817,10 +835,10 @@ pub fn getOrCreateMetadataForDecl(...@@ -817,10 +835,10 @@ pub fn getOrCreateMetadataForDecl(
817 const gop = try self.decls.getOrPut(gpa, decl_index);835 const gop = try self.decls.getOrPut(gpa, decl_index);
818 if (!gop.found_existing) {836 if (!gop.found_existing) {
819 const any_non_single_threaded = elf_file.base.comp.config.any_non_single_threaded;837 const any_non_single_threaded = elf_file.base.comp.config.any_non_single_threaded;
820 const symbol_index = try self.newAtom(elf_file);838 const symbol_index = try self.newSymbolWithAtom(gpa, 0);
821 const mod = elf_file.base.comp.module.?;839 const mod = elf_file.base.comp.module.?;
822 const decl = mod.declPtr(decl_index);840 const decl = mod.declPtr(decl_index);
823 const sym = elf_file.symbol(symbol_index);841 const sym = self.symbol(symbol_index);
824 if (decl.getOwnedVariable(mod)) |variable| {842 if (decl.getOwnedVariable(mod)) |variable| {
825 if (variable.is_threadlocal and any_non_single_threaded) {843 if (variable.is_threadlocal and any_non_single_threaded) {
826 sym.flags.is_tls = true;844 sym.flags.is_tls = true;
...@@ -909,8 +927,8 @@ fn updateDeclCode(...@@ -909,8 +927,8 @@ fn updateDeclCode(
909 target_util.minFunctionAlignment(mod.getTarget()),927 target_util.minFunctionAlignment(mod.getTarget()),
910 );928 );
911929
912 const sym = elf_file.symbol(sym_index);930 const sym = self.symbol(sym_index);
913 const esym = &self.local_esyms.items(.elf_sym)[sym.esym_index];931 const esym = &self.symtab.items(.elf_sym)[sym.esym_index];
914 const atom_ptr = sym.atom(elf_file).?;932 const atom_ptr = sym.atom(elf_file).?;
915 const name_offset = try self.strtab.insert(gpa, decl.fqn.toSlice(ip));933 const name_offset = try self.strtab.insert(gpa, decl.fqn.toSlice(ip));
916934
...@@ -940,7 +958,7 @@ fn updateDeclCode(...@@ -940,7 +958,7 @@ fn updateDeclCode(
940 if (!elf_file.base.isRelocatable()) {958 if (!elf_file.base.isRelocatable()) {
941 log.debug(" (writing new offset table entry)", .{});959 log.debug(" (writing new offset table entry)", .{});
942 assert(sym.flags.has_zig_got);960 assert(sym.flags.has_zig_got);
943 const extra = sym.extra(elf_file).?;961 const extra = sym.extra(elf_file);
944 try elf_file.zig_got.writeOne(elf_file, extra.zig_got);962 try elf_file.zig_got.writeOne(elf_file, extra.zig_got);
945 }963 }
946 }964 }
...@@ -1007,8 +1025,8 @@ fn updateTlv(...@@ -1007,8 +1025,8 @@ fn updateTlv(
10071025
1008 const required_alignment = decl.getAlignment(pt);1026 const required_alignment = decl.getAlignment(pt);
10091027
1010 const sym = elf_file.symbol(sym_index);1028 const sym = self.symbol(sym_index);
1011 const esym = &self.local_esyms.items(.elf_sym)[sym.esym_index];1029 const esym = &self.symtab.items(.elf_sym)[sym.esym_index];
1012 const atom_ptr = sym.atom(elf_file).?;1030 const atom_ptr = sym.atom(elf_file).?;
1013 const name_offset = try self.strtab.insert(gpa, decl.fqn.toSlice(ip));1031 const name_offset = try self.strtab.insert(gpa, decl.fqn.toSlice(ip));
10141032
...@@ -1064,7 +1082,7 @@ pub fn updateFunc(...@@ -1064,7 +1082,7 @@ pub fn updateFunc(
10641082
1065 const sym_index = try self.getOrCreateMetadataForDecl(elf_file, decl_index);1083 const sym_index = try self.getOrCreateMetadataForDecl(elf_file, decl_index);
1066 self.freeUnnamedConsts(elf_file, decl_index);1084 self.freeUnnamedConsts(elf_file, decl_index);
1067 elf_file.symbol(sym_index).atom(elf_file).?.freeRelocs(elf_file);1085 self.symbol(sym_index).atom(elf_file).?.freeRelocs(elf_file);
10681086
1069 var code_buffer = std.ArrayList(u8).init(gpa);1087 var code_buffer = std.ArrayList(u8).init(gpa);
1070 defer code_buffer.deinit();1088 defer code_buffer.deinit();
...@@ -1096,7 +1114,7 @@ pub fn updateFunc(...@@ -1096,7 +1114,7 @@ pub fn updateFunc(
1096 try self.updateDeclCode(elf_file, pt, decl_index, sym_index, shndx, code, elf.STT_FUNC);1114 try self.updateDeclCode(elf_file, pt, decl_index, sym_index, shndx, code, elf.STT_FUNC);
10971115
1098 if (decl_state) |*ds| {1116 if (decl_state) |*ds| {
1099 const sym = elf_file.symbol(sym_index);1117 const sym = self.symbol(sym_index);
1100 try self.dwarf.?.commitDeclState(1118 try self.dwarf.?.commitDeclState(
1101 pt,1119 pt,
1102 decl_index,1120 decl_index,
...@@ -1130,13 +1148,13 @@ pub fn updateDecl(...@@ -1130,13 +1148,13 @@ pub fn updateDecl(
1130 const variable = decl.getOwnedVariable(mod).?;1148 const variable = decl.getOwnedVariable(mod).?;
1131 const name = decl.name.toSlice(&mod.intern_pool);1149 const name = decl.name.toSlice(&mod.intern_pool);
1132 const lib_name = variable.lib_name.toSlice(&mod.intern_pool);1150 const lib_name = variable.lib_name.toSlice(&mod.intern_pool);
1133 const esym_index = try self.getGlobalSymbol(elf_file, name, lib_name);1151 const sym_index = try self.getGlobalSymbol(elf_file, name, lib_name);
1134 elf_file.symbol(self.symbol(esym_index)).flags.needs_got = true;1152 self.symbol(sym_index).flags.needs_got = true;
1135 return;1153 return;
1136 }1154 }
11371155
1138 const sym_index = try self.getOrCreateMetadataForDecl(elf_file, decl_index);1156 const sym_index = try self.getOrCreateMetadataForDecl(elf_file, decl_index);
1139 elf_file.symbol(sym_index).atom(elf_file).?.freeRelocs(elf_file);1157 self.symbol(sym_index).atom(elf_file).?.freeRelocs(elf_file);
11401158
1141 const gpa = elf_file.base.comp.gpa;1159 const gpa = elf_file.base.comp.gpa;
1142 var code_buffer = std.ArrayList(u8).init(gpa);1160 var code_buffer = std.ArrayList(u8).init(gpa);
...@@ -1174,7 +1192,7 @@ pub fn updateDecl(...@@ -1174,7 +1192,7 @@ pub fn updateDecl(
1174 try self.updateDeclCode(elf_file, pt, decl_index, sym_index, shndx, code, elf.STT_OBJECT);1192 try self.updateDeclCode(elf_file, pt, decl_index, sym_index, shndx, code, elf.STT_OBJECT);
11751193
1176 if (decl_state) |*ds| {1194 if (decl_state) |*ds| {
1177 const sym = elf_file.symbol(sym_index);1195 const sym = self.symbol(sym_index);
1178 try self.dwarf.?.commitDeclState(1196 try self.dwarf.?.commitDeclState(
1179 pt,1197 pt,
1180 decl_index,1198 decl_index,
...@@ -1233,9 +1251,9 @@ fn updateLazySymbol(...@@ -1233,9 +1251,9 @@ fn updateLazySymbol(
1233 .code => elf_file.zig_text_section_index.?,1251 .code => elf_file.zig_text_section_index.?,
1234 .const_data => elf_file.zig_data_rel_ro_section_index.?,1252 .const_data => elf_file.zig_data_rel_ro_section_index.?,
1235 };1253 };
1236 const local_sym = elf_file.symbol(symbol_index);1254 const local_sym = self.symbol(symbol_index);
1237 local_sym.name_offset = name_str_index;1255 local_sym.name_offset = name_str_index;
1238 const local_esym = &self.local_esyms.items(.elf_sym)[local_sym.esym_index];1256 const local_esym = &self.symtab.items(.elf_sym)[local_sym.esym_index];
1239 local_esym.st_name = name_str_index;1257 local_esym.st_name = name_str_index;
1240 local_esym.st_info |= elf.STT_OBJECT;1258 local_esym.st_info |= elf.STT_OBJECT;
1241 local_esym.st_size = code.len;1259 local_esym.st_size = code.len;
...@@ -1323,7 +1341,8 @@ fn lowerConst(...@@ -1323,7 +1341,8 @@ fn lowerConst(
1323 var code_buffer = std.ArrayList(u8).init(gpa);1341 var code_buffer = std.ArrayList(u8).init(gpa);
1324 defer code_buffer.deinit();1342 defer code_buffer.deinit();
13251343
1326 const sym_index = try self.newAtom(elf_file);1344 const name_off = try self.addString(gpa, name);
1345 const sym_index = try self.newSymbolWithAtom(gpa, name_off);
13271346
1328 const res = try codegen.generateSymbol(1347 const res = try codegen.generateSymbol(
1329 &elf_file.base,1348 &elf_file.base,
...@@ -1339,27 +1358,19 @@ fn lowerConst(...@@ -1339,27 +1358,19 @@ fn lowerConst(
1339 .fail => |em| return .{ .fail = em },1358 .fail => |em| return .{ .fail = em },
1340 };1359 };
13411360
1342 const local_sym = elf_file.symbol(sym_index);1361 const local_sym = self.symbol(sym_index);
1343 const name_str_index = try self.strtab.insert(gpa, name);1362 const local_esym = &self.symtab.items(.elf_sym)[local_sym.esym_index];
1344 local_sym.name_offset = name_str_index;
1345 const local_esym = &self.local_esyms.items(.elf_sym)[local_sym.esym_index];
1346 local_esym.st_name = name_str_index;
1347 local_esym.st_info |= elf.STT_OBJECT;1363 local_esym.st_info |= elf.STT_OBJECT;
1348 local_esym.st_size = code.len;1364 local_esym.st_size = code.len;
1349 const atom_ptr = local_sym.atom(elf_file).?;1365 const atom_ptr = local_sym.atom(elf_file).?;
1350 atom_ptr.alive = true;1366 atom_ptr.alive = true;
1351 atom_ptr.name_offset = name_str_index;
1352 atom_ptr.alignment = required_alignment;1367 atom_ptr.alignment = required_alignment;
1353 atom_ptr.size = code.len;1368 atom_ptr.size = code.len;
1354 atom_ptr.output_section_index = output_section_index;1369 atom_ptr.output_section_index = output_section_index;
13551370
1356 try atom_ptr.allocate(elf_file);1371 try atom_ptr.allocate(elf_file);
1357 // TODO rename and re-audit this method
1358 errdefer self.freeDeclMetadata(elf_file, sym_index);1372 errdefer self.freeDeclMetadata(elf_file, sym_index);
13591373
1360 local_sym.value = 0;
1361 local_esym.st_value = 0;
1362
1363 const shdr = elf_file.shdrs.items[output_section_index];1374 const shdr = elf_file.shdrs.items[output_section_index];
1364 const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value));1375 const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value));
1365 try elf_file.base.file.?.pwriteAll(code, file_offset);1376 try elf_file.base.file.?.pwriteAll(code, file_offset);
...@@ -1401,9 +1412,9 @@ pub fn updateExports(...@@ -1401,9 +1412,9 @@ pub fn updateExports(
1401 },1412 },
1402 };1413 };
1403 const sym_index = metadata.symbol_index;1414 const sym_index = metadata.symbol_index;
1404 const esym_index = elf_file.symbol(sym_index).esym_index;1415 const esym_index = self.symbol(sym_index).esym_index;
1405 const esym = self.local_esyms.items(.elf_sym)[esym_index];1416 const esym = self.symtab.items(.elf_sym)[esym_index];
1406 const esym_shndx = self.local_esyms.items(.shndx)[esym_index];1417 const esym_shndx = self.symtab.items(.shndx)[esym_index];
14071418
1408 for (export_indices) |export_idx| {1419 for (export_indices) |export_idx| {
1409 const exp = mod.all_exports.items[export_idx];1420 const exp = mod.all_exports.items[export_idx];
...@@ -1437,22 +1448,27 @@ pub fn updateExports(...@@ -1437,22 +1448,27 @@ pub fn updateExports(
1437 const stt_bits: u8 = @as(u4, @truncate(esym.st_info));1448 const stt_bits: u8 = @as(u4, @truncate(esym.st_info));
1438 const exp_name = exp.opts.name.toSlice(&mod.intern_pool);1449 const exp_name = exp.opts.name.toSlice(&mod.intern_pool);
1439 const name_off = try self.strtab.insert(gpa, exp_name);1450 const name_off = try self.strtab.insert(gpa, exp_name);
1440 const global_esym_index = if (metadata.@"export"(self, exp_name)) |exp_index|1451 const global_sym_index = if (metadata.@"export"(self, exp_name)) |exp_index|
1441 exp_index.*1452 exp_index.*
1442 else blk: {1453 else blk: {
1443 const global_esym_index = try self.getGlobalSymbol(elf_file, exp_name, null);1454 const global_sym_index = try self.getGlobalSymbol(elf_file, exp_name, null);
1444 try metadata.exports.append(gpa, global_esym_index);1455 try metadata.exports.append(gpa, global_sym_index);
1445 break :blk global_esym_index;1456 break :blk global_sym_index;
1446 };1457 };
14471458
1448 const actual_esym_index = global_esym_index & symbol_mask;1459 const value = self.symbol(sym_index).value;
1449 const global_esym = &self.global_esyms.items(.elf_sym)[actual_esym_index];1460 const global_sym = self.symbol(global_sym_index);
1450 global_esym.st_value = @intCast(elf_file.symbol(sym_index).value);1461 global_sym.value = value;
1462 global_sym.flags.weak = exp.opts.linkage == .weak;
1463 global_sym.version_index = elf_file.default_sym_version;
1464 global_sym.ref = .{ .index = esym_shndx, .file = self.index };
1465 const global_esym = &self.symtab.items(.elf_sym)[global_sym.esym_index];
1466 global_esym.st_value = @intCast(value);
1451 global_esym.st_shndx = esym.st_shndx;1467 global_esym.st_shndx = esym.st_shndx;
1452 global_esym.st_info = (stb_bits << 4) | stt_bits;1468 global_esym.st_info = (stb_bits << 4) | stt_bits;
1453 global_esym.st_name = name_off;1469 global_esym.st_name = name_off;
1454 global_esym.st_size = esym.st_size;1470 global_esym.st_size = esym.st_size;
1455 self.global_esyms.items(.shndx)[actual_esym_index] = esym_shndx;1471 self.symtab.items(.shndx)[global_sym.esym_index] = esym_shndx;
1456 }1472 }
1457}1473}
14581474
...@@ -1488,16 +1504,10 @@ pub fn deleteExport(...@@ -1488,16 +1504,10 @@ pub fn deleteExport(
1488 const exp_name = name.toSlice(&mod.intern_pool);1504 const exp_name = name.toSlice(&mod.intern_pool);
1489 const esym_index = metadata.@"export"(self, exp_name) orelse return;1505 const esym_index = metadata.@"export"(self, exp_name) orelse return;
1490 log.debug("deleting export '{s}'", .{exp_name});1506 log.debug("deleting export '{s}'", .{exp_name});
1491 const esym = &self.global_esyms.items(.elf_sym)[esym_index.*];1507 const esym = &self.symtab.items(.elf_sym)[esym_index.*];
1492 _ = self.globals_lookup.remove(esym.st_name);1508 _ = self.globals_lookup.remove(esym.st_name);
1493 const sym_index = elf_file.resolver.get(esym.st_name).?;
1494 const sym = elf_file.symbol(sym_index);
1495 if (sym.file_index == self.index) {
1496 _ = elf_file.resolver.swapRemove(esym.st_name);
1497 sym.* = .{};
1498 }
1499 esym.* = Elf.null_sym;1509 esym.* = Elf.null_sym;
1500 self.global_esyms.items(.shndx)[esym_index.*] = elf.SHN_UNDEF;1510 self.symtab.items(.shndx)[esym_index.*] = elf.SHN_UNDEF;
1501}1511}
15021512
1503pub fn getGlobalSymbol(self: *ZigObject, elf_file: *Elf, name: []const u8, lib_name: ?[]const u8) !u32 {1513pub fn getGlobalSymbol(self: *ZigObject, elf_file: *Elf, name: []const u8, lib_name: ?[]const u8) !u32 {
...@@ -1506,16 +1516,19 @@ pub fn getGlobalSymbol(self: *ZigObject, elf_file: *Elf, name: []const u8, lib_n...@@ -1506,16 +1516,19 @@ pub fn getGlobalSymbol(self: *ZigObject, elf_file: *Elf, name: []const u8, lib_n
1506 const off = try self.strtab.insert(gpa, name);1516 const off = try self.strtab.insert(gpa, name);
1507 const lookup_gop = try self.globals_lookup.getOrPut(gpa, off);1517 const lookup_gop = try self.globals_lookup.getOrPut(gpa, off);
1508 if (!lookup_gop.found_existing) {1518 if (!lookup_gop.found_existing) {
1509 const esym_index = try self.addGlobalEsym(gpa);1519 lookup_gop.value_ptr.* = try self.newGlobalSymbol(gpa, off);
1510 const esym = self.elfSym(esym_index);
1511 esym.st_name = off;
1512 lookup_gop.value_ptr.* = esym_index;
1513 const gop = try elf_file.getOrPutGlobal(name);
1514 try self.global_symbols.append(gpa, gop.index);
1515 }1520 }
1516 return lookup_gop.value_ptr.*;1521 return lookup_gop.value_ptr.*;
1517}1522}
15181523
1524pub fn asFile(self: *ZigObject) File {
1525 return .{ .zig_object = self };
1526}
1527
1528fn addString(self: *ZigObject, allocator: Allocator, string: []const u8) !u32 {
1529 return self.strtab.insert(allocator, string);
1530}
1531
1519pub fn getString(self: ZigObject, off: u32) [:0]const u8 {1532pub fn getString(self: ZigObject, off: u32) [:0]const u8 {
1520 return self.strtab.getAssumeExists(off);1533 return self.strtab.getAssumeExists(off);
1521}1534}
...@@ -1586,6 +1599,77 @@ pub fn setAtomExtra(self: *ZigObject, index: u32, extra: Atom.Extra) void {...@@ -1586,6 +1599,77 @@ pub fn setAtomExtra(self: *ZigObject, index: u32, extra: Atom.Extra) void {
1586 }1599 }
1587}1600}
15881601
1602inline fn isGlobal(index: Symbol.Index) bool {
1603 return index & global_symbol_bit != 0;
1604}
1605
1606pub fn symbol(self: *ZigObject, index: Symbol.Index) *Symbol {
1607 const actual_index = index & symbol_mask;
1608 if (isGlobal(index)) return &self.symbols.items[self.global_symbols.items[actual_index]];
1609 return &self.symbols.items[self.local_symbols.items[actual_index]];
1610}
1611
1612pub fn resolveSymbol(self: ZigObject, index: Symbol.Index, elf_file: *Elf) Elf.Ref {
1613 if (isGlobal(index)) {
1614 const resolv = self.symbols_resolver.items[index & symbol_mask];
1615 return elf_file.resolver.get(resolv).?;
1616 }
1617 return .{ .index = index, .file = self.index };
1618}
1619
1620fn addSymbol(self: *ZigObject, allocator: Allocator) !Symbol.Index {
1621 try self.symbols.ensureUnusedCapacity(allocator, 1);
1622 return self.addSymbolAssumeCapacity();
1623}
1624
1625fn addSymbolAssumeCapacity(self: *ZigObject) Symbol.Index {
1626 const index: Symbol.Index = @intCast(self.symbols.items.len);
1627 self.symbols.appendAssumeCapacity(.{ .file_index = self.index });
1628 return index;
1629}
1630
1631pub fn addSymbolExtra(self: *ZigObject, allocator: Allocator, extra: Symbol.Extra) !u32 {
1632 const fields = @typeInfo(Symbol.Extra).Struct.fields;
1633 try self.symbols_extra.ensureUnusedCapacity(allocator, fields.len);
1634 return self.addSymbolExtraAssumeCapacity(extra);
1635}
1636
1637pub fn addSymbolExtraAssumeCapacity(self: *ZigObject, extra: Symbol.Extra) u32 {
1638 const index = @as(u32, @intCast(self.symbols_extra.items.len));
1639 const fields = @typeInfo(Symbol.Extra).Struct.fields;
1640 inline for (fields) |field| {
1641 self.symbols_extra.appendAssumeCapacity(switch (field.type) {
1642 u32 => @field(extra, field.name),
1643 else => @compileError("bad field type"),
1644 });
1645 }
1646 return index;
1647}
1648
1649pub fn symbolExtra(self: *ZigObject, index: u32) Symbol.Extra {
1650 const fields = @typeInfo(Symbol.Extra).Struct.fields;
1651 var i: usize = index;
1652 var result: Symbol.Extra = undefined;
1653 inline for (fields) |field| {
1654 @field(result, field.name) = switch (field.type) {
1655 u32 => self.symbols_extra.items[i],
1656 else => @compileError("bad field type"),
1657 };
1658 i += 1;
1659 }
1660 return result;
1661}
1662
1663pub fn setSymbolExtra(self: *ZigObject, index: u32, extra: Symbol.Extra) void {
1664 const fields = @typeInfo(Symbol.Extra).Struct.fields;
1665 inline for (fields, 0..) |field, i| {
1666 self.symbols_extra.items[index + i] = switch (field.type) {
1667 u32 => @field(extra, field.name),
1668 else => @compileError("bad field type"),
1669 };
1670 }
1671}
1672
1589pub fn fmtSymtab(self: *ZigObject, elf_file: *Elf) std.fmt.Formatter(formatSymtab) {1673pub fn fmtSymtab(self: *ZigObject, elf_file: *Elf) std.fmt.Formatter(formatSymtab) {
1590 return .{ .data = .{1674 return .{ .data = .{
1591 .self = self,1675 .self = self,
...@@ -1606,15 +1690,17 @@ fn formatSymtab(...@@ -1606,15 +1690,17 @@ fn formatSymtab(
1606) !void {1690) !void {
1607 _ = unused_fmt_string;1691 _ = unused_fmt_string;
1608 _ = options;1692 _ = options;
1693 const self = ctx.self;
1694 const elf_file = ctx.elf_file;
1609 try writer.writeAll(" locals\n");1695 try writer.writeAll(" locals\n");
1610 for (ctx.self.locals()) |index| {1696 for (self.local_symbols.items) |index| {
1611 const local = ctx.elf_file.symbol(index);1697 const local = self.symbols.items[index];
1612 try writer.print(" {}\n", .{local.fmt(ctx.elf_file)});1698 try writer.print(" {}\n", .{local.fmt(elf_file)});
1613 }1699 }
1614 try writer.writeAll(" globals\n");1700 try writer.writeAll(" globals\n");
1615 for (ctx.self.globals()) |index| {1701 for (ctx.self.global_symbols.items) |index| {
1616 const global = ctx.elf_file.symbol(index);1702 const global = self.symbols.items[index];
1617 try writer.print(" {}\n", .{global.fmt(ctx.elf_file)});1703 try writer.print(" {}\n", .{global.fmt(elf_file)});
1618 }1704 }
1619}1705}
16201706
...@@ -1658,9 +1744,9 @@ const DeclMetadata = struct {...@@ -1658,9 +1744,9 @@ const DeclMetadata = struct {
1658 /// A list of all exports aliases of this Decl.1744 /// A list of all exports aliases of this Decl.
1659 exports: std.ArrayListUnmanaged(Symbol.Index) = .{},1745 exports: std.ArrayListUnmanaged(Symbol.Index) = .{},
16601746
1661 fn @"export"(m: DeclMetadata, zig_object: *ZigObject, name: []const u8) ?*u32 {1747 fn @"export"(m: DeclMetadata, zo: *ZigObject, name: []const u8) ?*u32 {
1662 for (m.exports.items) |*exp| {1748 for (m.exports.items) |*exp| {
1663 const exp_name = zig_object.getString(zig_object.elfSym(exp.*).st_name);1749 const exp_name = zo.getString(zo.symbol(exp.*).name_offset);
1664 if (mem.eql(u8, name, exp_name)) return exp;1750 if (mem.eql(u8, name, exp_name)) return exp;
1665 }1751 }
1666 return null;1752 return null;
src/link/Elf/eh_frame.zig+13-8
...@@ -145,10 +145,10 @@ pub const Cie = struct {...@@ -145,10 +145,10 @@ pub const Cie = struct {
145 if (cie_rel.r_addend != other_rel.r_addend) return false;145 if (cie_rel.r_addend != other_rel.r_addend) return false;
146146
147 const cie_object = elf_file.file(cie.file_index).?.object;147 const cie_object = elf_file.file(cie.file_index).?.object;
148 const cie_ref = cie_object.resolveSymbol(cie_rel.r_sym(), elf_file);
148 const other_object = elf_file.file(other.file_index).?.object;149 const other_object = elf_file.file(other.file_index).?.object;
149 const cie_sym = cie_object.symbols.items[cie_rel.r_sym()];150 const other_ref = other_object.resolveSymbol(other_rel.r_sym(), elf_file);
150 const other_sym = other_object.symbols.items[other_rel.r_sym()];151 if (!cie_ref.eql(other_ref)) return false;
151 if (!std.mem.eql(u8, std.mem.asBytes(&cie_sym), std.mem.asBytes(&other_sym))) return false;
152 }152 }
153 return true;153 return true;
154 }154 }
...@@ -339,7 +339,8 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void {...@@ -339,7 +339,8 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void {
339 const contents = cie.data(elf_file);339 const contents = cie.data(elf_file);
340340
341 for (cie.relocs(elf_file)) |rel| {341 for (cie.relocs(elf_file)) |rel| {
342 const sym = elf_file.symbol(object.symbols.items[rel.r_sym()]);342 const ref = object.resolveSymbol(rel.r_sym(), elf_file);
343 const sym = elf_file.symbol(ref).?;
343 resolveReloc(cie, sym, rel, elf_file, contents) catch |err| switch (err) {344 resolveReloc(cie, sym, rel, elf_file, contents) catch |err| switch (err) {
344 error.RelocFailure => has_reloc_errors = true,345 error.RelocFailure => has_reloc_errors = true,
345 else => |e| return e,346 else => |e| return e,
...@@ -366,7 +367,8 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void {...@@ -366,7 +367,8 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void {
366 );367 );
367368
368 for (fde.relocs(elf_file)) |rel| {369 for (fde.relocs(elf_file)) |rel| {
369 const sym = elf_file.symbol(object.symbols.items[rel.r_sym()]);370 const ref = object.resolveSymbol(rel.r_sym(), elf_file);
371 const sym = elf_file.symbol(ref).?;
370 resolveReloc(fde, sym, rel, elf_file, contents) catch |err| switch (err) {372 resolveReloc(fde, sym, rel, elf_file, contents) catch |err| switch (err) {
371 error.RelocFailure => has_reloc_errors = true,373 error.RelocFailure => has_reloc_errors = true,
372 else => |e| return e,374 else => |e| return e,
...@@ -452,7 +454,8 @@ pub fn writeEhFrameRelocs(elf_file: *Elf, writer: anytype) !void {...@@ -452,7 +454,8 @@ pub fn writeEhFrameRelocs(elf_file: *Elf, writer: anytype) !void {
452 for (object.cies.items) |cie| {454 for (object.cies.items) |cie| {
453 if (!cie.alive) continue;455 if (!cie.alive) continue;
454 for (cie.relocs(elf_file)) |rel| {456 for (cie.relocs(elf_file)) |rel| {
455 const sym = elf_file.symbol(object.symbols.items[rel.r_sym()]);457 const ref = object.resolveSymbol(rel.r_sym(), elf_file);
458 const sym = elf_file.symbol(ref).?;
456 const out_rel = emitReloc(elf_file, cie, sym, rel);459 const out_rel = emitReloc(elf_file, cie, sym, rel);
457 try writer.writeStruct(out_rel);460 try writer.writeStruct(out_rel);
458 }461 }
...@@ -461,7 +464,8 @@ pub fn writeEhFrameRelocs(elf_file: *Elf, writer: anytype) !void {...@@ -461,7 +464,8 @@ pub fn writeEhFrameRelocs(elf_file: *Elf, writer: anytype) !void {
461 for (object.fdes.items) |fde| {464 for (object.fdes.items) |fde| {
462 if (!fde.alive) continue;465 if (!fde.alive) continue;
463 for (fde.relocs(elf_file)) |rel| {466 for (fde.relocs(elf_file)) |rel| {
464 const sym = elf_file.symbol(object.symbols.items[rel.r_sym()]);467 const ref = object.resolveSymbol(rel.r_sym(), elf_file);
468 const sym = elf_file.symbol(ref).?;
465 const out_rel = emitReloc(elf_file, fde, sym, rel);469 const out_rel = emitReloc(elf_file, fde, sym, rel);
466 try writer.writeStruct(out_rel);470 try writer.writeStruct(out_rel);
467 }471 }
...@@ -513,7 +517,8 @@ pub fn writeEhFrameHdr(elf_file: *Elf, writer: anytype) !void {...@@ -513,7 +517,8 @@ pub fn writeEhFrameHdr(elf_file: *Elf, writer: anytype) !void {
513 const relocs = fde.relocs(elf_file);517 const relocs = fde.relocs(elf_file);
514 assert(relocs.len > 0); // Should this be an error? Things are completely broken anyhow if this trips...518 assert(relocs.len > 0); // Should this be an error? Things are completely broken anyhow if this trips...
515 const rel = relocs[0];519 const rel = relocs[0];
516 const sym = elf_file.symbol(object.symbols.items[rel.r_sym()]);520 const ref = object.resolveSymbol(rel.r_sym(), elf_file);
521 const sym = elf_file.symbol(ref).?;
517 const P = @as(i64, @intCast(fde.address(elf_file)));522 const P = @as(i64, @intCast(fde.address(elf_file)));
518 const S = @as(i64, @intCast(sym.address(.{}, elf_file)));523 const S = @as(i64, @intCast(sym.address(.{}, elf_file)));
519 const A = rel.r_addend;524 const A = rel.r_addend;
src/link/Elf/file.zig+80-25
...@@ -61,20 +61,10 @@ pub const File = union(enum) {...@@ -61,20 +61,10 @@ pub const File = union(enum) {
61 return (@as(u32, base) << 24) + file.index();61 return (@as(u32, base) << 24) + file.index();
62 }62 }
6363
64 pub fn resolveSymbols(file: File, elf_file: *Elf) void {64 pub fn resolveSymbols(file: File, elf_file: *Elf) !void {
65 switch (file) {65 return switch (file) {
66 inline else => |x| x.resolveSymbols(elf_file),66 inline else => |x| x.resolveSymbols(elf_file),
67 }67 };
68 }
69
70 pub fn resetGlobals(file: File, elf_file: *Elf) void {
71 for (file.globals()) |global_index| {
72 const global = elf_file.symbol(global_index);
73 const name_offset = global.name_offset;
74 global.* = .{};
75 global.name_offset = name_offset;
76 global.flags.global = true;
77 }
78 }68 }
7969
80 pub fn setAlive(file: File) void {70 pub fn setAlive(file: File) void {
...@@ -98,6 +88,77 @@ pub const File = union(enum) {...@@ -98,6 +88,77 @@ pub const File = union(enum) {
98 }88 }
99 }89 }
10090
91 pub fn createSymbolIndirection(file: File, elf_file: *Elf) !void {
92 const impl = struct {
93 fn impl(sym: *Symbol, ref: Elf.Ref, ef: *Elf) !void {
94 if (!sym.isLocal(ef) and !sym.flags.has_dynamic) {
95 log.debug("'{s}' is non-local", .{sym.name(ef)});
96 try ef.dynsym.addSymbol(ref, ef);
97 }
98 if (sym.flags.needs_got) {
99 log.debug("'{s}' needs GOT", .{sym.name(ef)});
100 _ = try ef.got.addGotSymbol(ref, ef);
101 }
102 if (sym.flags.needs_plt) {
103 if (sym.flags.is_canonical) {
104 log.debug("'{s}' needs CPLT", .{sym.name(ef)});
105 sym.flags.@"export" = true;
106 try ef.plt.addSymbol(ref, ef);
107 } else if (sym.flags.needs_got) {
108 log.debug("'{s}' needs PLTGOT", .{sym.name(ef)});
109 try ef.plt_got.addSymbol(ref, ef);
110 } else {
111 log.debug("'{s}' needs PLT", .{sym.name(ef)});
112 try ef.plt.addSymbol(ref, ef);
113 }
114 }
115 if (sym.flags.needs_copy_rel and !sym.flags.has_copy_rel) {
116 log.debug("'{s}' needs COPYREL", .{sym.name(ef)});
117 try ef.copy_rel.addSymbol(ref, ef);
118 }
119 if (sym.flags.needs_tlsgd) {
120 log.debug("'{s}' needs TLSGD", .{sym.name(ef)});
121 try ef.got.addTlsGdSymbol(ref, ef);
122 }
123 if (sym.flags.needs_gottp) {
124 log.debug("'{s}' needs GOTTP", .{sym.name(ef)});
125 try ef.got.addGotTpSymbol(ref, ef);
126 }
127 if (sym.flags.needs_tlsdesc) {
128 log.debug("'{s}' needs TLSDESC", .{sym.name(ef)});
129 try ef.got.addTlsDescSymbol(ref, ef);
130 }
131 }
132 }.impl;
133
134 switch (file) {
135 .zig_object => |x| {
136 for (x.local_symbols.items, 0..) |idx, i| {
137 const sym = &x.symbols.items[idx];
138 const ref = x.resolveSymbol(@intCast(i), elf_file);
139 const ref_sym = elf_file.symbol(ref) orelse continue;
140 if (ref_sym.file(elf_file).?.index() != x.index) continue;
141 try impl(sym, ref, elf_file);
142 }
143 for (x.global_symbols.items, 0..) |idx, i| {
144 const sym = &x.symbols.items[idx];
145 const ref = x.resolveSymbol(@intCast(i | ZigObject.global_symbol_bit), elf_file);
146 const ref_sym = elf_file.symbol(ref) orelse continue;
147 if (ref_sym.file(elf_file).?.index() != x.index) continue;
148 try impl(sym, ref, elf_file);
149 }
150 },
151 inline else => |x| {
152 for (x.symbols.items, 0..) |*sym, i| {
153 const ref = x.resolveSymbol(@intCast(i), elf_file);
154 const ref_sym = elf_file.symbol(ref) orelse continue;
155 if (ref_sym.file(elf_file).?.index() != x.index) continue;
156 try impl(sym, ref, elf_file);
157 }
158 },
159 }
160 }
161
101 pub fn atom(file: File, atom_index: Atom.Index) ?*Atom {162 pub fn atom(file: File, atom_index: Atom.Index) ?*Atom {
102 return switch (file) {163 return switch (file) {
103 .shared_object => unreachable,164 .shared_object => unreachable,
...@@ -144,23 +205,16 @@ pub const File = union(enum) {...@@ -144,23 +205,16 @@ pub const File = union(enum) {
144 };205 };
145 }206 }
146207
147 pub fn symbol(file: File, ind: Symbol.Index) Symbol.Index {208 pub fn resolveSymbol(file: File, ind: Symbol.Index, elf_file: *Elf) Elf.Ref {
148 return switch (file) {209 return switch (file) {
149 .zig_object => |x| x.symbol(ind),210 inline else => |x| x.resolveSymbol(ind, elf_file),
150 inline else => |x| x.symbols.items[ind],
151 };211 };
152 }212 }
153213
154 pub fn locals(file: File) []const Symbol.Index {214 pub fn symbol(file: File, ind: Symbol.Index) *Symbol {
155 return switch (file) {215 return switch (file) {
156 .linker_defined, .shared_object => &[0]Symbol.Index{},216 .zig_object => |x| x.symbol(ind),
157 inline else => |x| x.locals(),217 inline else => |x| &x.symbols.items[ind],
158 };
159 }
160
161 pub fn globals(file: File) []const Symbol.Index {
162 return switch (file) {
163 inline else => |x| x.globals(),
164 };218 };
165 }219 }
166220
...@@ -237,6 +291,7 @@ pub const File = union(enum) {...@@ -237,6 +291,7 @@ pub const File = union(enum) {
237291
238const std = @import("std");292const std = @import("std");
239const elf = std.elf;293const elf = std.elf;
294const log = std.log.scoped(.link);
240295
241const Allocator = std.mem.Allocator;296const Allocator = std.mem.Allocator;
242const Archive = @import("Archive.zig");297const Archive = @import("Archive.zig");
src/link/Elf/gc.zig+81-58
...@@ -1,71 +1,84 @@...@@ -1,71 +1,84 @@
1pub fn gcAtoms(elf_file: *Elf) !void {1pub fn gcAtoms(elf_file: *Elf) !void {
2 const comp = elf_file.base.comp;2 const comp = elf_file.base.comp;
3 const gpa = comp.gpa;3 const gpa = comp.gpa;
4 const num_files = elf_file.objects.items.len + @intFromBool(elf_file.zig_object_index != null);
5 var files = try std.ArrayList(File.Index).initCapacity(gpa, num_files);
6 defer files.deinit();
7 if (elf_file.zig_object_index) |index| files.appendAssumeCapacity(index);
8 for (elf_file.objects.items) |index| files.appendAssumeCapacity(index);
9
10 var roots = std.ArrayList(*Atom).init(gpa);4 var roots = std.ArrayList(*Atom).init(gpa);
11 defer roots.deinit();5 defer roots.deinit();
12 try collectRoots(&roots, files.items, elf_file);6 try collectRoots(&roots, elf_file);
13
14 mark(roots, elf_file);7 mark(roots, elf_file);
15 prune(files.items, elf_file);8 prune(elf_file);
16}9}
1710
18fn collectRoots(roots: *std.ArrayList(*Atom), files: []const File.Index, elf_file: *Elf) !void {11fn collectRoots(roots: *std.ArrayList(*Atom), elf_file: *Elf) !void {
19 if (elf_file.linkerDefinedPtr()) |obj| {12 if (elf_file.linkerDefinedPtr()) |obj| {
20 if (obj.entry_index) |index| {13 if (obj.entrySymbol(elf_file)) |sym| {
21 const global = elf_file.symbol(index);14 try markSymbol(sym, roots, elf_file);
22 try markSymbol(global, roots, elf_file);
23 }15 }
24 }16 }
2517
26 for (files) |index| {18 if (elf_file.zigObjectPtr()) |zo| {
27 for (elf_file.file(index).?.globals()) |global_index| {19 for (0..zo.global_symbols.items.len) |i| {
28 const global = elf_file.symbol(global_index);20 const ref = zo.resolveSymbol(@intCast(i | ZigObject.global_symbol_bit), elf_file);
29 if (global.file(elf_file)) |file| {21 const sym = elf_file.symbol(ref) orelse continue;
30 if (file.index() == index and global.flags.@"export")22 if (sym.file(elf_file).?.index() != zo.index) continue;
31 try markSymbol(global, roots, elf_file);23 if (sym.flags.@"export") {
24 try markSymbol(sym, roots, elf_file);
32 }25 }
33 }26 }
34 }27 }
3528
36 for (files) |index| {29 for (elf_file.objects.items) |index| {
37 const file = elf_file.file(index).?;30 const object = elf_file.file(index).?.object;
3831 for (0..object.globals().len) |i| {
39 for (file.atoms()) |atom_index| {32 const ref = object.resolveSymbol(@intCast(i), elf_file);
40 const atom = file.atom(atom_index) orelse continue;33 const sym = elf_file.symbol(ref) orelse continue;
41 if (!atom.alive) continue;34 if (sym.file(elf_file).?.index() != object.index) continue;
4235 if (sym.flags.@"export") {
43 const shdr = atom.inputShdr(elf_file);36 try markSymbol(sym, roots, elf_file);
44 const name = atom.name(elf_file);37 }
45 const is_gc_root = blk: {
46 if (shdr.sh_flags & elf.SHF_GNU_RETAIN != 0) break :blk true;
47 if (shdr.sh_type == elf.SHT_NOTE) break :blk true;
48 if (shdr.sh_type == elf.SHT_PREINIT_ARRAY) break :blk true;
49 if (shdr.sh_type == elf.SHT_INIT_ARRAY) break :blk true;
50 if (shdr.sh_type == elf.SHT_FINI_ARRAY) break :blk true;
51 if (mem.startsWith(u8, name, ".ctors")) break :blk true;
52 if (mem.startsWith(u8, name, ".dtors")) break :blk true;
53 if (mem.startsWith(u8, name, ".init")) break :blk true;
54 if (mem.startsWith(u8, name, ".fini")) break :blk true;
55 if (Elf.isCIdentifier(name)) break :blk true;
56 break :blk false;
57 };
58 if (is_gc_root and markAtom(atom)) try roots.append(atom);
59 if (shdr.sh_flags & elf.SHF_ALLOC == 0) atom.visited = true;
60 }38 }
39 }
6140
62 // Mark every atom referenced by CIE as alive.41 const atomRoots = struct {
63 for (file.cies()) |cie| {42 fn atomRoots(file: File, rs: anytype, ef: *Elf) !void {
64 for (cie.relocs(elf_file)) |rel| {43 for (file.atoms()) |atom_index| {
65 const sym = elf_file.symbol(file.symbol(rel.r_sym()));44 const atom = file.atom(atom_index) orelse continue;
66 try markSymbol(sym, roots, elf_file);45 if (!atom.alive) continue;
46
47 const shdr = atom.inputShdr(ef);
48 const name = atom.name(ef);
49 const is_gc_root = blk: {
50 if (shdr.sh_flags & elf.SHF_GNU_RETAIN != 0) break :blk true;
51 if (shdr.sh_type == elf.SHT_NOTE) break :blk true;
52 if (shdr.sh_type == elf.SHT_PREINIT_ARRAY) break :blk true;
53 if (shdr.sh_type == elf.SHT_INIT_ARRAY) break :blk true;
54 if (shdr.sh_type == elf.SHT_FINI_ARRAY) break :blk true;
55 if (mem.startsWith(u8, name, ".ctors")) break :blk true;
56 if (mem.startsWith(u8, name, ".dtors")) break :blk true;
57 if (mem.startsWith(u8, name, ".init")) break :blk true;
58 if (mem.startsWith(u8, name, ".fini")) break :blk true;
59 if (Elf.isCIdentifier(name)) break :blk true;
60 break :blk false;
61 };
62 if (is_gc_root and markAtom(atom)) try rs.append(atom);
63 if (shdr.sh_flags & elf.SHF_ALLOC == 0) atom.visited = true;
64 }
65
66 // Mark every atom referenced by CIE as alive.
67 for (file.cies()) |cie| {
68 for (cie.relocs(ef)) |rel| {
69 const ref = file.resolveSymbol(rel.r_sym(), ef);
70 const sym = ef.symbol(ref) orelse continue;
71 try markSymbol(sym, rs, ef);
72 }
67 }73 }
68 }74 }
75 }.atomRoots;
76
77 if (elf_file.zigObjectPtr()) |zo| {
78 try atomRoots(zo.asFile(), roots, elf_file);
79 }
80 for (elf_file.objects.items) |index| {
81 try atomRoots(elf_file.file(index).?, roots, elf_file);
69 }82 }
70}83}
7184
...@@ -92,7 +105,8 @@ fn markLive(atom: *Atom, elf_file: *Elf) void {...@@ -92,7 +105,8 @@ fn markLive(atom: *Atom, elf_file: *Elf) void {
92105
93 for (atom.fdes(elf_file)) |fde| {106 for (atom.fdes(elf_file)) |fde| {
94 for (fde.relocs(elf_file)[1..]) |rel| {107 for (fde.relocs(elf_file)[1..]) |rel| {
95 const target_sym = elf_file.symbol(file.symbol(rel.r_sym()));108 const ref = file.resolveSymbol(rel.r_sym(), elf_file);
109 const target_sym = elf_file.symbol(ref) orelse continue;
96 const target_atom = target_sym.atom(elf_file) orelse continue;110 const target_atom = target_sym.atom(elf_file) orelse continue;
97 target_atom.alive = true;111 target_atom.alive = true;
98 gc_track_live_log.debug("{}marking live atom({d})", .{ track_live_level, target_atom.atom_index });112 gc_track_live_log.debug("{}marking live atom({d})", .{ track_live_level, target_atom.atom_index });
...@@ -101,7 +115,8 @@ fn markLive(atom: *Atom, elf_file: *Elf) void {...@@ -101,7 +115,8 @@ fn markLive(atom: *Atom, elf_file: *Elf) void {
101 }115 }
102116
103 for (atom.relocs(elf_file)) |rel| {117 for (atom.relocs(elf_file)) |rel| {
104 const target_sym = elf_file.symbol(file.symbol(rel.r_sym()));118 const ref = file.resolveSymbol(rel.r_sym(), elf_file);
119 const target_sym = elf_file.symbol(ref) orelse continue;
105 if (target_sym.mergeSubsection(elf_file)) |msub| {120 if (target_sym.mergeSubsection(elf_file)) |msub| {
106 msub.alive = true;121 msub.alive = true;
107 continue;122 continue;
...@@ -120,16 +135,23 @@ fn mark(roots: std.ArrayList(*Atom), elf_file: *Elf) void {...@@ -120,16 +135,23 @@ fn mark(roots: std.ArrayList(*Atom), elf_file: *Elf) void {
120 }135 }
121}136}
122137
123fn prune(files: []const File.Index, elf_file: *Elf) void {138fn prune(elf_file: *Elf) void {
124 for (files) |index| {139 const pruneInFile = struct {
125 const file = elf_file.file(index).?;140 fn pruneInFile(file: File, ef: *Elf) void {
126 for (file.atoms()) |atom_index| {141 for (file.atoms()) |atom_index| {
127 const atom = file.atom(atom_index) orelse continue;142 const atom = file.atom(atom_index) orelse continue;
128 if (atom.alive and !atom.visited) {143 if (atom.alive and !atom.visited) {
129 atom.alive = false;144 atom.alive = false;
130 atom.markFdesDead(elf_file);145 atom.markFdesDead(ef);
146 }
131 }147 }
132 }148 }
149 }.pruneInFile;
150 if (elf_file.zigObjectPtr()) |zo| {
151 pruneInFile(zo.asFile(), elf_file);
152 }
153 for (elf_file.objects.items) |index| {
154 pruneInFile(elf_file.file(index).?, elf_file);
133 }155 }
134}156}
135157
...@@ -181,3 +203,4 @@ const Atom = @import("Atom.zig");...@@ -181,3 +203,4 @@ const Atom = @import("Atom.zig");
181const Elf = @import("../Elf.zig");203const Elf = @import("../Elf.zig");
182const File = @import("file.zig").File;204const File = @import("file.zig").File;
183const Symbol = @import("Symbol.zig");205const Symbol = @import("Symbol.zig");
206const ZigObject = @import("ZigObject.zig");
src/link/Elf/relocatable.zig+2-2
...@@ -37,7 +37,7 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]co...@@ -37,7 +37,7 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]co
3737
38 // First, we flush relocatable object file generated with our backends.38 // First, we flush relocatable object file generated with our backends.
39 if (elf_file.zigObjectPtr()) |zig_object| {39 if (elf_file.zigObjectPtr()) |zig_object| {
40 zig_object.resolveSymbols(elf_file);40 try zig_object.resolveSymbols(elf_file);
41 try elf_file.addCommentString();41 try elf_file.addCommentString();
42 try elf_file.finalizeMergeSections();42 try elf_file.finalizeMergeSections();
43 zig_object.claimUnresolvedObject(elf_file);43 zig_object.claimUnresolvedObject(elf_file);
...@@ -383,7 +383,7 @@ fn updateComdatGroupsSizes(elf_file: *Elf) void {...@@ -383,7 +383,7 @@ fn updateComdatGroupsSizes(elf_file: *Elf) void {
383 shdr.sh_size = cg.size(elf_file);383 shdr.sh_size = cg.size(elf_file);
384 shdr.sh_link = elf_file.symtab_section_index.?;384 shdr.sh_link = elf_file.symtab_section_index.?;
385385
386 const sym = elf_file.symbol(cg.symbol(elf_file));386 const sym = cg.symbol(elf_file);
387 shdr.sh_info = sym.outputSymtabIndex(elf_file) orelse387 shdr.sh_info = sym.outputSymtabIndex(elf_file) orelse
388 elf_file.sectionSymbolOutputSymtabIndex(sym.outputShndx(elf_file).?);388 elf_file.sectionSymbolOutputSymtabIndex(sym.outputShndx(elf_file).?);
389 }389 }
src/link/Elf/synthetic_sections.zig+130-135
...@@ -251,15 +251,16 @@ pub const ZigGotSection = struct {...@@ -251,15 +251,16 @@ pub const ZigGotSection = struct {
251 pub fn addSymbol(zig_got: *ZigGotSection, sym_index: Symbol.Index, elf_file: *Elf) !Index {251 pub fn addSymbol(zig_got: *ZigGotSection, sym_index: Symbol.Index, elf_file: *Elf) !Index {
252 const comp = elf_file.base.comp;252 const comp = elf_file.base.comp;
253 const gpa = comp.gpa;253 const gpa = comp.gpa;
254 const zo = elf_file.zigObjectPtr().?;
254 const index = try zig_got.allocateEntry(gpa);255 const index = try zig_got.allocateEntry(gpa);
255 const entry = &zig_got.entries.items[index];256 const entry = &zig_got.entries.items[index];
256 entry.* = sym_index;257 entry.* = sym_index;
257 const symbol = elf_file.symbol(sym_index);258 const symbol = zo.symbol(sym_index);
258 symbol.flags.has_zig_got = true;259 symbol.flags.has_zig_got = true;
259 if (elf_file.isEffectivelyDynLib() or (elf_file.base.isExe() and comp.config.pie)) {260 if (elf_file.isEffectivelyDynLib() or (elf_file.base.isExe() and comp.config.pie)) {
260 zig_got.flags.needs_rela = true;261 zig_got.flags.needs_rela = true;
261 }262 }
262 try symbol.addExtra(.{ .zig_got = index }, elf_file);263 symbol.addExtra(.{ .zig_got = index }, elf_file);
263 return index;264 return index;
264 }265 }
265266
...@@ -282,6 +283,7 @@ pub const ZigGotSection = struct {...@@ -282,6 +283,7 @@ pub const ZigGotSection = struct {
282 }283 }
283284
284 pub fn writeOne(zig_got: *ZigGotSection, elf_file: *Elf, index: Index) !void {285 pub fn writeOne(zig_got: *ZigGotSection, elf_file: *Elf, index: Index) !void {
286 const zo = elf_file.zigObjectPtr().?;
285 if (zig_got.flags.dirty) {287 if (zig_got.flags.dirty) {
286 const needed_size = zig_got.size(elf_file);288 const needed_size = zig_got.size(elf_file);
287 try elf_file.growAllocSection(elf_file.zig_got_section_index.?, needed_size);289 try elf_file.growAllocSection(elf_file.zig_got_section_index.?, needed_size);
...@@ -293,7 +295,7 @@ pub const ZigGotSection = struct {...@@ -293,7 +295,7 @@ pub const ZigGotSection = struct {
293 const off = zig_got.entryOffset(index, elf_file);295 const off = zig_got.entryOffset(index, elf_file);
294 const vaddr: u64 = @intCast(zig_got.entryAddress(index, elf_file));296 const vaddr: u64 = @intCast(zig_got.entryAddress(index, elf_file));
295 const entry = zig_got.entries.items[index];297 const entry = zig_got.entries.items[index];
296 const value = elf_file.symbol(entry).address(.{}, elf_file);298 const value = zo.symbol(entry).address(.{}, elf_file);
297 switch (entry_size) {299 switch (entry_size) {
298 2 => {300 2 => {
299 var buf: [2]u8 = undefined;301 var buf: [2]u8 = undefined;
...@@ -336,8 +338,9 @@ pub const ZigGotSection = struct {...@@ -336,8 +338,9 @@ pub const ZigGotSection = struct {
336 }338 }
337339
338 pub fn writeAll(zig_got: ZigGotSection, elf_file: *Elf, writer: anytype) !void {340 pub fn writeAll(zig_got: ZigGotSection, elf_file: *Elf, writer: anytype) !void {
341 const zo = elf_file.zigObjectPtr().?;
339 for (zig_got.entries.items) |entry| {342 for (zig_got.entries.items) |entry| {
340 const symbol = elf_file.symbol(entry);343 const symbol = zo.symbol(entry);
341 const value = symbol.address(.{ .plt = false }, elf_file);344 const value = symbol.address(.{ .plt = false }, elf_file);
342 try writeInt(value, elf_file, writer);345 try writeInt(value, elf_file, writer);
343 }346 }
...@@ -351,9 +354,10 @@ pub const ZigGotSection = struct {...@@ -351,9 +354,10 @@ pub const ZigGotSection = struct {
351 const comp = elf_file.base.comp;354 const comp = elf_file.base.comp;
352 const gpa = comp.gpa;355 const gpa = comp.gpa;
353 const cpu_arch = elf_file.getTarget().cpu.arch;356 const cpu_arch = elf_file.getTarget().cpu.arch;
357 const zo = elf_file.zigObjectPtr().?;
354 try elf_file.rela_dyn.ensureUnusedCapacity(gpa, zig_got.numRela());358 try elf_file.rela_dyn.ensureUnusedCapacity(gpa, zig_got.numRela());
355 for (zig_got.entries.items) |entry| {359 for (zig_got.entries.items) |entry| {
356 const symbol = elf_file.symbol(entry);360 const symbol = zo.symbol(entry);
357 const offset = symbol.zigGotAddress(elf_file);361 const offset = symbol.zigGotAddress(elf_file);
358 elf_file.addRelaDynAssumeCapacity(.{362 elf_file.addRelaDynAssumeCapacity(.{
359 .offset = @intCast(offset),363 .offset = @intCast(offset),
...@@ -364,16 +368,18 @@ pub const ZigGotSection = struct {...@@ -364,16 +368,18 @@ pub const ZigGotSection = struct {
364 }368 }
365369
366 pub fn updateSymtabSize(zig_got: *ZigGotSection, elf_file: *Elf) void {370 pub fn updateSymtabSize(zig_got: *ZigGotSection, elf_file: *Elf) void {
371 const zo = elf_file.zigObjectPtr().?;
367 zig_got.output_symtab_ctx.nlocals = @as(u32, @intCast(zig_got.entries.items.len));372 zig_got.output_symtab_ctx.nlocals = @as(u32, @intCast(zig_got.entries.items.len));
368 for (zig_got.entries.items) |entry| {373 for (zig_got.entries.items) |entry| {
369 const name = elf_file.symbol(entry).name(elf_file);374 const name = zo.symbol(entry).name(elf_file);
370 zig_got.output_symtab_ctx.strsize += @as(u32, @intCast(name.len + "$ziggot".len)) + 1;375 zig_got.output_symtab_ctx.strsize += @as(u32, @intCast(name.len + "$ziggot".len)) + 1;
371 }376 }
372 }377 }
373378
374 pub fn writeSymtab(zig_got: ZigGotSection, elf_file: *Elf) void {379 pub fn writeSymtab(zig_got: ZigGotSection, elf_file: *Elf) void {
380 const zo = elf_file.zigObjectPtr().?;
375 for (zig_got.entries.items, zig_got.output_symtab_ctx.ilocal.., 0..) |entry, ilocal, index| {381 for (zig_got.entries.items, zig_got.output_symtab_ctx.ilocal.., 0..) |entry, ilocal, index| {
376 const symbol = elf_file.symbol(entry);382 const symbol = zo.symbol(entry);
377 const symbol_name = symbol.name(elf_file);383 const symbol_name = symbol.name(elf_file);
378 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));384 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
379 elf_file.strtab.appendSliceAssumeCapacity(symbol_name);385 elf_file.strtab.appendSliceAssumeCapacity(symbol_name);
...@@ -409,15 +415,18 @@ pub const ZigGotSection = struct {...@@ -409,15 +415,18 @@ pub const ZigGotSection = struct {
409 ) !void {415 ) !void {
410 _ = options;416 _ = options;
411 _ = unused_fmt_string;417 _ = unused_fmt_string;
418 const zig_got = ctx.zig_got;
419 const elf_file = ctx.elf_file;
412 try writer.writeAll(".zig.got\n");420 try writer.writeAll(".zig.got\n");
413 for (ctx.zig_got.entries.items, 0..) |entry, index| {421 for (zig_got.entries.items, 0..) |entry, index| {
414 const symbol = ctx.elf_file.symbol(entry);422 const zo = elf_file.zigObjectPtr().?;
423 const symbol = zo.symbol(entry);
415 try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{424 try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{
416 index,425 index,
417 ctx.zig_got.entryAddress(@intCast(index), ctx.elf_file),426 zig_got.entryAddress(@intCast(index), elf_file),
418 entry,427 entry,
419 symbol.address(.{}, ctx.elf_file),428 symbol.address(.{}, elf_file),
420 symbol.name(ctx.elf_file),429 symbol.name(elf_file),
421 });430 });
422 }431 }
423 }432 }
...@@ -446,7 +455,7 @@ pub const GotSection = struct {...@@ -446,7 +455,7 @@ pub const GotSection = struct {
446455
447 const Entry = struct {456 const Entry = struct {
448 tag: Tag,457 tag: Tag,
449 symbol_index: Symbol.Index,458 ref: Elf.Ref,
450 cell_index: Index,459 cell_index: Index,
451460
452 /// Returns how many indexes in the GOT this entry uses.461 /// Returns how many indexes in the GOT this entry uses.
...@@ -477,25 +486,25 @@ pub const GotSection = struct {...@@ -477,25 +486,25 @@ pub const GotSection = struct {
477 const last = got.entries.items[index - 1];486 const last = got.entries.items[index - 1];
478 break :blk last.cell_index + @as(Index, @intCast(last.len()));487 break :blk last.cell_index + @as(Index, @intCast(last.len()));
479 } else 0;488 } else 0;
480 entry.* = .{ .tag = undefined, .symbol_index = undefined, .cell_index = cell_index };489 entry.* = .{ .tag = undefined, .ref = undefined, .cell_index = cell_index };
481 return index;490 return index;
482 }491 }
483492
484 pub fn addGotSymbol(got: *GotSection, sym_index: Symbol.Index, elf_file: *Elf) !Index {493 pub fn addGotSymbol(got: *GotSection, ref: Elf.Ref, elf_file: *Elf) !Index {
485 const comp = elf_file.base.comp;494 const comp = elf_file.base.comp;
486 const gpa = comp.gpa;495 const gpa = comp.gpa;
487 const index = try got.allocateEntry(gpa);496 const index = try got.allocateEntry(gpa);
488 const entry = &got.entries.items[index];497 const entry = &got.entries.items[index];
489 entry.tag = .got;498 entry.tag = .got;
490 entry.symbol_index = sym_index;499 entry.ref = ref;
491 const symbol = elf_file.symbol(sym_index);500 const symbol = elf_file.symbol(ref).?;
492 symbol.flags.has_got = true;501 symbol.flags.has_got = true;
493 if (symbol.flags.import or symbol.isIFunc(elf_file) or502 if (symbol.flags.import or symbol.isIFunc(elf_file) or
494 ((elf_file.isEffectivelyDynLib() or (elf_file.base.isExe() and comp.config.pie)) and !symbol.isAbs(elf_file)))503 ((elf_file.isEffectivelyDynLib() or (elf_file.base.isExe() and comp.config.pie)) and !symbol.isAbs(elf_file)))
495 {504 {
496 got.flags.needs_rela = true;505 got.flags.needs_rela = true;
497 }506 }
498 try symbol.addExtra(.{ .got = index }, elf_file);507 symbol.addExtra(.{ .got = index }, elf_file);
499 return index;508 return index;
500 }509 }
501510
...@@ -506,48 +515,48 @@ pub const GotSection = struct {...@@ -506,48 +515,48 @@ pub const GotSection = struct {
506 const index = try got.allocateEntry(gpa);515 const index = try got.allocateEntry(gpa);
507 const entry = &got.entries.items[index];516 const entry = &got.entries.items[index];
508 entry.tag = .tlsld;517 entry.tag = .tlsld;
509 entry.symbol_index = undefined; // unused518 entry.ref = .{ .index = 0, .file = 0 }; // unused
510 got.flags.needs_rela = true;519 got.flags.needs_rela = true;
511 got.tlsld_index = index;520 got.tlsld_index = index;
512 }521 }
513522
514 pub fn addTlsGdSymbol(got: *GotSection, sym_index: Symbol.Index, elf_file: *Elf) !void {523 pub fn addTlsGdSymbol(got: *GotSection, ref: Elf.Ref, elf_file: *Elf) !void {
515 const comp = elf_file.base.comp;524 const comp = elf_file.base.comp;
516 const gpa = comp.gpa;525 const gpa = comp.gpa;
517 const index = try got.allocateEntry(gpa);526 const index = try got.allocateEntry(gpa);
518 const entry = &got.entries.items[index];527 const entry = &got.entries.items[index];
519 entry.tag = .tlsgd;528 entry.tag = .tlsgd;
520 entry.symbol_index = sym_index;529 entry.ref = ref;
521 const symbol = elf_file.symbol(sym_index);530 const symbol = elf_file.symbol(ref).?;
522 symbol.flags.has_tlsgd = true;531 symbol.flags.has_tlsgd = true;
523 if (symbol.flags.import or elf_file.isEffectivelyDynLib()) got.flags.needs_rela = true;532 if (symbol.flags.import or elf_file.isEffectivelyDynLib()) got.flags.needs_rela = true;
524 try symbol.addExtra(.{ .tlsgd = index }, elf_file);533 symbol.addExtra(.{ .tlsgd = index }, elf_file);
525 }534 }
526535
527 pub fn addGotTpSymbol(got: *GotSection, sym_index: Symbol.Index, elf_file: *Elf) !void {536 pub fn addGotTpSymbol(got: *GotSection, ref: Elf.Ref, elf_file: *Elf) !void {
528 const comp = elf_file.base.comp;537 const comp = elf_file.base.comp;
529 const gpa = comp.gpa;538 const gpa = comp.gpa;
530 const index = try got.allocateEntry(gpa);539 const index = try got.allocateEntry(gpa);
531 const entry = &got.entries.items[index];540 const entry = &got.entries.items[index];
532 entry.tag = .gottp;541 entry.tag = .gottp;
533 entry.symbol_index = sym_index;542 entry.ref = ref;
534 const symbol = elf_file.symbol(sym_index);543 const symbol = elf_file.symbol(ref).?;
535 symbol.flags.has_gottp = true;544 symbol.flags.has_gottp = true;
536 if (symbol.flags.import or elf_file.isEffectivelyDynLib()) got.flags.needs_rela = true;545 if (symbol.flags.import or elf_file.isEffectivelyDynLib()) got.flags.needs_rela = true;
537 try symbol.addExtra(.{ .gottp = index }, elf_file);546 symbol.addExtra(.{ .gottp = index }, elf_file);
538 }547 }
539548
540 pub fn addTlsDescSymbol(got: *GotSection, sym_index: Symbol.Index, elf_file: *Elf) !void {549 pub fn addTlsDescSymbol(got: *GotSection, ref: Elf.Ref, elf_file: *Elf) !void {
541 const comp = elf_file.base.comp;550 const comp = elf_file.base.comp;
542 const gpa = comp.gpa;551 const gpa = comp.gpa;
543 const index = try got.allocateEntry(gpa);552 const index = try got.allocateEntry(gpa);
544 const entry = &got.entries.items[index];553 const entry = &got.entries.items[index];
545 entry.tag = .tlsdesc;554 entry.tag = .tlsdesc;
546 entry.symbol_index = sym_index;555 entry.ref = ref;
547 const symbol = elf_file.symbol(sym_index);556 const symbol = elf_file.symbol(ref).?;
548 symbol.flags.has_tlsdesc = true;557 symbol.flags.has_tlsdesc = true;
549 got.flags.needs_rela = true;558 got.flags.needs_rela = true;
550 try symbol.addExtra(.{ .tlsdesc = index }, elf_file);559 symbol.addExtra(.{ .tlsdesc = index }, elf_file);
551 }560 }
552561
553 pub fn size(got: GotSection, elf_file: *Elf) usize {562 pub fn size(got: GotSection, elf_file: *Elf) usize {
...@@ -564,10 +573,7 @@ pub const GotSection = struct {...@@ -564,10 +573,7 @@ pub const GotSection = struct {
564 const apply_relocs = true; // TODO add user option for this573 const apply_relocs = true; // TODO add user option for this
565574
566 for (got.entries.items) |entry| {575 for (got.entries.items) |entry| {
567 const symbol = switch (entry.tag) {576 const symbol = elf_file.symbol(entry.ref);
568 .tlsld => null,
569 inline else => elf_file.symbol(entry.symbol_index),
570 };
571 switch (entry.tag) {577 switch (entry.tag) {
572 .got => {578 .got => {
573 const value = blk: {579 const value = blk: {
...@@ -637,11 +643,8 @@ pub const GotSection = struct {...@@ -637,11 +643,8 @@ pub const GotSection = struct {
637 try elf_file.rela_dyn.ensureUnusedCapacity(gpa, got.numRela(elf_file));643 try elf_file.rela_dyn.ensureUnusedCapacity(gpa, got.numRela(elf_file));
638644
639 for (got.entries.items) |entry| {645 for (got.entries.items) |entry| {
640 const symbol = switch (entry.tag) {646 const symbol = elf_file.symbol(entry.ref);
641 .tlsld => null,647 const extra = if (symbol) |s| s.extra(elf_file) else null;
642 inline else => elf_file.symbol(entry.symbol_index),
643 };
644 const extra = if (symbol) |s| s.extra(elf_file).? else null;
645648
646 switch (entry.tag) {649 switch (entry.tag) {
647 .got => {650 .got => {
...@@ -740,10 +743,7 @@ pub const GotSection = struct {...@@ -740,10 +743,7 @@ pub const GotSection = struct {
740 const is_dyn_lib = elf_file.isEffectivelyDynLib();743 const is_dyn_lib = elf_file.isEffectivelyDynLib();
741 var num: usize = 0;744 var num: usize = 0;
742 for (got.entries.items) |entry| {745 for (got.entries.items) |entry| {
743 const symbol = switch (entry.tag) {746 const symbol = elf_file.symbol(entry.ref);
744 .tlsld => null,
745 inline else => elf_file.symbol(entry.symbol_index),
746 };
747 switch (entry.tag) {747 switch (entry.tag) {
748 .got => if (symbol.?.flags.import or symbol.?.isIFunc(elf_file) or748 .got => if (symbol.?.flags.import or symbol.?.isIFunc(elf_file) or
749 ((elf_file.isEffectivelyDynLib() or (elf_file.base.isExe() and comp.config.pie)) and749 ((elf_file.isEffectivelyDynLib() or (elf_file.base.isExe() and comp.config.pie)) and
...@@ -775,24 +775,15 @@ pub const GotSection = struct {...@@ -775,24 +775,15 @@ pub const GotSection = struct {
775 pub fn updateSymtabSize(got: *GotSection, elf_file: *Elf) void {775 pub fn updateSymtabSize(got: *GotSection, elf_file: *Elf) void {
776 got.output_symtab_ctx.nlocals = @as(u32, @intCast(got.entries.items.len));776 got.output_symtab_ctx.nlocals = @as(u32, @intCast(got.entries.items.len));
777 for (got.entries.items) |entry| {777 for (got.entries.items) |entry| {
778 const symbol_name = switch (entry.tag) {778 const symbol_name = if (elf_file.symbol(entry.ref)) |sym| sym.name(elf_file) else "";
779 .tlsld => "",
780 inline else => elf_file.symbol(entry.symbol_index).name(elf_file),
781 };
782 got.output_symtab_ctx.strsize += @as(u32, @intCast(symbol_name.len + @tagName(entry.tag).len)) + 1 + 1;779 got.output_symtab_ctx.strsize += @as(u32, @intCast(symbol_name.len + @tagName(entry.tag).len)) + 1 + 1;
783 }780 }
784 }781 }
785782
786 pub fn writeSymtab(got: GotSection, elf_file: *Elf) void {783 pub fn writeSymtab(got: GotSection, elf_file: *Elf) void {
787 for (got.entries.items, got.output_symtab_ctx.ilocal..) |entry, ilocal| {784 for (got.entries.items, got.output_symtab_ctx.ilocal..) |entry, ilocal| {
788 const symbol = switch (entry.tag) {785 const symbol = elf_file.symbol(entry.ref);
789 .tlsld => null,786 const symbol_name = if (symbol) |s| s.name(elf_file) else "";
790 inline else => elf_file.symbol(entry.symbol_index),
791 };
792 const symbol_name = switch (entry.tag) {
793 .tlsld => "",
794 inline else => symbol.?.name(elf_file),
795 };
796 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));787 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
797 elf_file.strtab.appendSliceAssumeCapacity(symbol_name);788 elf_file.strtab.appendSliceAssumeCapacity(symbol_name);
798 elf_file.strtab.appendAssumeCapacity('$');789 elf_file.strtab.appendAssumeCapacity('$');
...@@ -828,36 +819,38 @@ pub const GotSection = struct {...@@ -828,36 +819,38 @@ pub const GotSection = struct {
828 ) !void {819 ) !void {
829 _ = options;820 _ = options;
830 _ = unused_fmt_string;821 _ = unused_fmt_string;
822 const got = ctx.got;
823 const elf_file = ctx.elf_file;
831 try writer.writeAll("GOT\n");824 try writer.writeAll("GOT\n");
832 for (ctx.got.entries.items) |entry| {825 for (got.entries.items) |entry| {
833 const symbol = ctx.elf_file.symbol(entry.symbol_index);826 const symbol = elf_file.symbol(entry.ref).?;
834 try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{827 try writer.print(" {d}@0x{x} => {}@0x{x} ({s})\n", .{
835 entry.cell_index,828 entry.cell_index,
836 entry.address(ctx.elf_file),829 entry.address(elf_file),
837 entry.symbol_index,830 entry.ref,
838 symbol.address(.{}, ctx.elf_file),831 symbol.address(.{}, elf_file),
839 symbol.name(ctx.elf_file),832 symbol.name(elf_file),
840 });833 });
841 }834 }
842 }835 }
843};836};
844837
845pub const PltSection = struct {838pub const PltSection = struct {
846 symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},839 symbols: std.ArrayListUnmanaged(Elf.Ref) = .{},
847 output_symtab_ctx: Elf.SymtabCtx = .{},840 output_symtab_ctx: Elf.SymtabCtx = .{},
848841
849 pub fn deinit(plt: *PltSection, allocator: Allocator) void {842 pub fn deinit(plt: *PltSection, allocator: Allocator) void {
850 plt.symbols.deinit(allocator);843 plt.symbols.deinit(allocator);
851 }844 }
852845
853 pub fn addSymbol(plt: *PltSection, sym_index: Symbol.Index, elf_file: *Elf) !void {846 pub fn addSymbol(plt: *PltSection, ref: Elf.Ref, elf_file: *Elf) !void {
854 const comp = elf_file.base.comp;847 const comp = elf_file.base.comp;
855 const gpa = comp.gpa;848 const gpa = comp.gpa;
856 const index = @as(u32, @intCast(plt.symbols.items.len));849 const index = @as(u32, @intCast(plt.symbols.items.len));
857 const symbol = elf_file.symbol(sym_index);850 const symbol = elf_file.symbol(ref).?;
858 symbol.flags.has_plt = true;851 symbol.flags.has_plt = true;
859 try symbol.addExtra(.{ .plt = index }, elf_file);852 symbol.addExtra(.{ .plt = index }, elf_file);
860 try plt.symbols.append(gpa, sym_index);853 try plt.symbols.append(gpa, ref);
861 }854 }
862855
863 pub fn size(plt: PltSection, elf_file: *Elf) usize {856 pub fn size(plt: PltSection, elf_file: *Elf) usize {
...@@ -895,10 +888,10 @@ pub const PltSection = struct {...@@ -895,10 +888,10 @@ pub const PltSection = struct {
895 const gpa = comp.gpa;888 const gpa = comp.gpa;
896 const cpu_arch = elf_file.getTarget().cpu.arch;889 const cpu_arch = elf_file.getTarget().cpu.arch;
897 try elf_file.rela_plt.ensureUnusedCapacity(gpa, plt.numRela());890 try elf_file.rela_plt.ensureUnusedCapacity(gpa, plt.numRela());
898 for (plt.symbols.items) |sym_index| {891 for (plt.symbols.items) |ref| {
899 const sym = elf_file.symbol(sym_index);892 const sym = elf_file.symbol(ref).?;
900 assert(sym.flags.import);893 assert(sym.flags.import);
901 const extra = sym.extra(elf_file).?;894 const extra = sym.extra(elf_file);
902 const r_offset: u64 = @intCast(sym.gotPltAddress(elf_file));895 const r_offset: u64 = @intCast(sym.gotPltAddress(elf_file));
903 const r_sym: u64 = extra.dynamic;896 const r_sym: u64 = extra.dynamic;
904 const r_type = relocation.encode(.jump_slot, cpu_arch);897 const r_type = relocation.encode(.jump_slot, cpu_arch);
...@@ -916,16 +909,16 @@ pub const PltSection = struct {...@@ -916,16 +909,16 @@ pub const PltSection = struct {
916909
917 pub fn updateSymtabSize(plt: *PltSection, elf_file: *Elf) void {910 pub fn updateSymtabSize(plt: *PltSection, elf_file: *Elf) void {
918 plt.output_symtab_ctx.nlocals = @as(u32, @intCast(plt.symbols.items.len));911 plt.output_symtab_ctx.nlocals = @as(u32, @intCast(plt.symbols.items.len));
919 for (plt.symbols.items) |sym_index| {912 for (plt.symbols.items) |ref| {
920 const name = elf_file.symbol(sym_index).name(elf_file);913 const name = elf_file.symbol(ref).?.name(elf_file);
921 plt.output_symtab_ctx.strsize += @as(u32, @intCast(name.len + "$plt".len)) + 1;914 plt.output_symtab_ctx.strsize += @as(u32, @intCast(name.len + "$plt".len)) + 1;
922 }915 }
923 }916 }
924917
925 pub fn writeSymtab(plt: PltSection, elf_file: *Elf) void {918 pub fn writeSymtab(plt: PltSection, elf_file: *Elf) void {
926 const cpu_arch = elf_file.getTarget().cpu.arch;919 const cpu_arch = elf_file.getTarget().cpu.arch;
927 for (plt.symbols.items, plt.output_symtab_ctx.ilocal..) |sym_index, ilocal| {920 for (plt.symbols.items, plt.output_symtab_ctx.ilocal..) |ref, ilocal| {
928 const sym = elf_file.symbol(sym_index);921 const sym = elf_file.symbol(ref).?;
929 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));922 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
930 elf_file.strtab.appendSliceAssumeCapacity(sym.name(elf_file));923 elf_file.strtab.appendSliceAssumeCapacity(sym.name(elf_file));
931 elf_file.strtab.appendSliceAssumeCapacity("$plt");924 elf_file.strtab.appendSliceAssumeCapacity("$plt");
...@@ -958,15 +951,17 @@ pub const PltSection = struct {...@@ -958,15 +951,17 @@ pub const PltSection = struct {
958 ) !void {951 ) !void {
959 _ = options;952 _ = options;
960 _ = unused_fmt_string;953 _ = unused_fmt_string;
954 const plt = ctx.plt;
955 const elf_file = ctx.elf_file;
961 try writer.writeAll("PLT\n");956 try writer.writeAll("PLT\n");
962 for (ctx.plt.symbols.items, 0..) |symbol_index, i| {957 for (plt.symbols.items, 0..) |ref, i| {
963 const symbol = ctx.elf_file.symbol(symbol_index);958 const symbol = elf_file.symbol(ref).?;
964 try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{959 try writer.print(" {d}@0x{x} => {}@0x{x} ({s})\n", .{
965 i,960 i,
966 symbol.pltAddress(ctx.elf_file),961 symbol.pltAddress(elf_file),
967 symbol_index,962 ref,
968 symbol.address(.{}, ctx.elf_file),963 symbol.address(.{}, elf_file),
969 symbol.name(ctx.elf_file),964 symbol.name(elf_file),
970 });965 });
971 }966 }
972 }967 }
...@@ -988,8 +983,8 @@ pub const PltSection = struct {...@@ -988,8 +983,8 @@ pub const PltSection = struct {
988 try writer.writeAll(&preamble);983 try writer.writeAll(&preamble);
989 try writer.writeByteNTimes(0xcc, preambleSize(.x86_64) - preamble.len);984 try writer.writeByteNTimes(0xcc, preambleSize(.x86_64) - preamble.len);
990985
991 for (plt.symbols.items, 0..) |sym_index, i| {986 for (plt.symbols.items, 0..) |ref, i| {
992 const sym = elf_file.symbol(sym_index);987 const sym = elf_file.symbol(ref).?;
993 const target_addr = sym.gotPltAddress(elf_file);988 const target_addr = sym.gotPltAddress(elf_file);
994 const source_addr = sym.pltAddress(elf_file);989 const source_addr = sym.pltAddress(elf_file);
995 disp = @as(i64, @intCast(target_addr)) - @as(i64, @intCast(source_addr + 12)) - 4;990 disp = @as(i64, @intCast(target_addr)) - @as(i64, @intCast(source_addr + 12)) - 4;
...@@ -1037,8 +1032,8 @@ pub const PltSection = struct {...@@ -1037,8 +1032,8 @@ pub const PltSection = struct {
1037 }1032 }
1038 }1033 }
10391034
1040 for (plt.symbols.items) |sym_index| {1035 for (plt.symbols.items) |ref| {
1041 const sym = elf_file.symbol(sym_index);1036 const sym = elf_file.symbol(ref).?;
1042 const target_addr = sym.gotPltAddress(elf_file);1037 const target_addr = sym.gotPltAddress(elf_file);
1043 const source_addr = sym.pltAddress(elf_file);1038 const source_addr = sym.pltAddress(elf_file);
1044 const pages = try aarch64_util.calcNumberOfPages(source_addr, target_addr);1039 const pages = try aarch64_util.calcNumberOfPages(source_addr, target_addr);
...@@ -1075,7 +1070,7 @@ pub const GotPltSection = struct {...@@ -1075,7 +1070,7 @@ pub const GotPltSection = struct {
1075 _ = got_plt;1070 _ = got_plt;
1076 {1071 {
1077 // [0]: _DYNAMIC1072 // [0]: _DYNAMIC
1078 const symbol = elf_file.symbol(elf_file.linkerDefinedPtr().?.dynamic_index.?);1073 const symbol = elf_file.linkerDefinedPtr().?.dynamicSymbol(elf_file).?;
1079 try writer.writeInt(u64, @intCast(symbol.address(.{}, elf_file)), .little);1074 try writer.writeInt(u64, @intCast(symbol.address(.{}, elf_file)), .little);
1080 }1075 }
1081 // [1]: 0x01076 // [1]: 0x0
...@@ -1093,22 +1088,22 @@ pub const GotPltSection = struct {...@@ -1093,22 +1088,22 @@ pub const GotPltSection = struct {
1093};1088};
10941089
1095pub const PltGotSection = struct {1090pub const PltGotSection = struct {
1096 symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},1091 symbols: std.ArrayListUnmanaged(Elf.Ref) = .{},
1097 output_symtab_ctx: Elf.SymtabCtx = .{},1092 output_symtab_ctx: Elf.SymtabCtx = .{},
10981093
1099 pub fn deinit(plt_got: *PltGotSection, allocator: Allocator) void {1094 pub fn deinit(plt_got: *PltGotSection, allocator: Allocator) void {
1100 plt_got.symbols.deinit(allocator);1095 plt_got.symbols.deinit(allocator);
1101 }1096 }
11021097
1103 pub fn addSymbol(plt_got: *PltGotSection, sym_index: Symbol.Index, elf_file: *Elf) !void {1098 pub fn addSymbol(plt_got: *PltGotSection, ref: Elf.Ref, elf_file: *Elf) !void {
1104 const comp = elf_file.base.comp;1099 const comp = elf_file.base.comp;
1105 const gpa = comp.gpa;1100 const gpa = comp.gpa;
1106 const index = @as(u32, @intCast(plt_got.symbols.items.len));1101 const index = @as(u32, @intCast(plt_got.symbols.items.len));
1107 const symbol = elf_file.symbol(sym_index);1102 const symbol = elf_file.symbol(ref).?;
1108 symbol.flags.has_plt = true;1103 symbol.flags.has_plt = true;
1109 symbol.flags.has_got = true;1104 symbol.flags.has_got = true;
1110 try symbol.addExtra(.{ .plt_got = index }, elf_file);1105 symbol.addExtra(.{ .plt_got = index }, elf_file);
1111 try plt_got.symbols.append(gpa, sym_index);1106 try plt_got.symbols.append(gpa, ref);
1112 }1107 }
11131108
1114 pub fn size(plt_got: PltGotSection, elf_file: *Elf) usize {1109 pub fn size(plt_got: PltGotSection, elf_file: *Elf) usize {
...@@ -1134,15 +1129,15 @@ pub const PltGotSection = struct {...@@ -1134,15 +1129,15 @@ pub const PltGotSection = struct {
11341129
1135 pub fn updateSymtabSize(plt_got: *PltGotSection, elf_file: *Elf) void {1130 pub fn updateSymtabSize(plt_got: *PltGotSection, elf_file: *Elf) void {
1136 plt_got.output_symtab_ctx.nlocals = @as(u32, @intCast(plt_got.symbols.items.len));1131 plt_got.output_symtab_ctx.nlocals = @as(u32, @intCast(plt_got.symbols.items.len));
1137 for (plt_got.symbols.items) |sym_index| {1132 for (plt_got.symbols.items) |ref| {
1138 const name = elf_file.symbol(sym_index).name(elf_file);1133 const name = elf_file.symbol(ref).?.name(elf_file);
1139 plt_got.output_symtab_ctx.strsize += @as(u32, @intCast(name.len + "$pltgot".len)) + 1;1134 plt_got.output_symtab_ctx.strsize += @as(u32, @intCast(name.len + "$pltgot".len)) + 1;
1140 }1135 }
1141 }1136 }
11421137
1143 pub fn writeSymtab(plt_got: PltGotSection, elf_file: *Elf) void {1138 pub fn writeSymtab(plt_got: PltGotSection, elf_file: *Elf) void {
1144 for (plt_got.symbols.items, plt_got.output_symtab_ctx.ilocal..) |sym_index, ilocal| {1139 for (plt_got.symbols.items, plt_got.output_symtab_ctx.ilocal..) |ref, ilocal| {
1145 const sym = elf_file.symbol(sym_index);1140 const sym = elf_file.symbol(ref).?;
1146 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));1141 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
1147 elf_file.strtab.appendSliceAssumeCapacity(sym.name(elf_file));1142 elf_file.strtab.appendSliceAssumeCapacity(sym.name(elf_file));
1148 elf_file.strtab.appendSliceAssumeCapacity("$pltgot");1143 elf_file.strtab.appendSliceAssumeCapacity("$pltgot");
...@@ -1160,8 +1155,8 @@ pub const PltGotSection = struct {...@@ -1160,8 +1155,8 @@ pub const PltGotSection = struct {
11601155
1161 const x86_64 = struct {1156 const x86_64 = struct {
1162 pub fn write(plt_got: PltGotSection, elf_file: *Elf, writer: anytype) !void {1157 pub fn write(plt_got: PltGotSection, elf_file: *Elf, writer: anytype) !void {
1163 for (plt_got.symbols.items) |sym_index| {1158 for (plt_got.symbols.items) |ref| {
1164 const sym = elf_file.symbol(sym_index);1159 const sym = elf_file.symbol(ref).?;
1165 const target_addr = sym.gotAddress(elf_file);1160 const target_addr = sym.gotAddress(elf_file);
1166 const source_addr = sym.pltGotAddress(elf_file);1161 const source_addr = sym.pltGotAddress(elf_file);
1167 const disp = @as(i64, @intCast(target_addr)) - @as(i64, @intCast(source_addr + 6)) - 4;1162 const disp = @as(i64, @intCast(target_addr)) - @as(i64, @intCast(source_addr + 6)) - 4;
...@@ -1178,8 +1173,8 @@ pub const PltGotSection = struct {...@@ -1178,8 +1173,8 @@ pub const PltGotSection = struct {
11781173
1179 const aarch64 = struct {1174 const aarch64 = struct {
1180 fn write(plt_got: PltGotSection, elf_file: *Elf, writer: anytype) !void {1175 fn write(plt_got: PltGotSection, elf_file: *Elf, writer: anytype) !void {
1181 for (plt_got.symbols.items) |sym_index| {1176 for (plt_got.symbols.items) |ref| {
1182 const sym = elf_file.symbol(sym_index);1177 const sym = elf_file.symbol(ref).?;
1183 const target_addr = sym.gotAddress(elf_file);1178 const target_addr = sym.gotAddress(elf_file);
1184 const source_addr = sym.pltGotAddress(elf_file);1179 const source_addr = sym.pltGotAddress(elf_file);
1185 const pages = try aarch64_util.calcNumberOfPages(source_addr, target_addr);1180 const pages = try aarch64_util.calcNumberOfPages(source_addr, target_addr);
...@@ -1204,56 +1199,56 @@ pub const PltGotSection = struct {...@@ -1204,56 +1199,56 @@ pub const PltGotSection = struct {
1204};1199};
12051200
1206pub const CopyRelSection = struct {1201pub const CopyRelSection = struct {
1207 symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},1202 symbols: std.ArrayListUnmanaged(Elf.Ref) = .{},
12081203
1209 pub fn deinit(copy_rel: *CopyRelSection, allocator: Allocator) void {1204 pub fn deinit(copy_rel: *CopyRelSection, allocator: Allocator) void {
1210 copy_rel.symbols.deinit(allocator);1205 copy_rel.symbols.deinit(allocator);
1211 }1206 }
12121207
1213 pub fn addSymbol(copy_rel: *CopyRelSection, sym_index: Symbol.Index, elf_file: *Elf) !void {1208 pub fn addSymbol(copy_rel: *CopyRelSection, ref: Elf.Ref, elf_file: *Elf) !void {
1214 const comp = elf_file.base.comp;1209 const comp = elf_file.base.comp;
1215 const gpa = comp.gpa;1210 const gpa = comp.gpa;
1216 const index = @as(u32, @intCast(copy_rel.symbols.items.len));1211 const index = @as(u32, @intCast(copy_rel.symbols.items.len));
1217 const symbol = elf_file.symbol(sym_index);1212 const symbol = elf_file.symbol(ref).?;
1218 symbol.flags.import = true;1213 symbol.flags.import = true;
1219 symbol.flags.@"export" = true;1214 symbol.flags.@"export" = true;
1220 symbol.flags.has_copy_rel = true;1215 symbol.flags.has_copy_rel = true;
1221 symbol.flags.weak = false;1216 symbol.flags.weak = false;
1222 try symbol.addExtra(.{ .copy_rel = index }, elf_file);1217 symbol.addExtra(.{ .copy_rel = index }, elf_file);
1223 try copy_rel.symbols.append(gpa, sym_index);1218 try copy_rel.symbols.append(gpa, ref);
12241219
1225 const shared_object = symbol.file(elf_file).?.shared_object;1220 const shared_object = symbol.file(elf_file).?.shared_object;
1226 if (shared_object.aliases == null) {1221 if (shared_object.aliases == null) {
1227 try shared_object.initSymbolAliases(elf_file);1222 try shared_object.initSymbolAliases(elf_file);
1228 }1223 }
12291224
1230 const aliases = shared_object.symbolAliases(sym_index, elf_file);1225 const aliases = shared_object.symbolAliases(ref.index, elf_file);
1231 for (aliases) |alias| {1226 for (aliases) |alias| {
1232 if (alias == sym_index) continue;1227 if (alias == ref.index) continue;
1233 const alias_sym = elf_file.symbol(alias);1228 const alias_sym = &shared_object.symbols.items[alias];
1234 alias_sym.flags.import = true;1229 alias_sym.flags.import = true;
1235 alias_sym.flags.@"export" = true;1230 alias_sym.flags.@"export" = true;
1236 alias_sym.flags.has_copy_rel = true;1231 alias_sym.flags.has_copy_rel = true;
1237 alias_sym.flags.needs_copy_rel = true;1232 alias_sym.flags.needs_copy_rel = true;
1238 alias_sym.flags.weak = false;1233 alias_sym.flags.weak = false;
1239 try elf_file.dynsym.addSymbol(alias, elf_file);1234 try elf_file.dynsym.addSymbol(.{ .index = alias, .file = shared_object.index }, elf_file);
1240 }1235 }
1241 }1236 }
12421237
1243 pub fn updateSectionSize(copy_rel: CopyRelSection, shndx: u32, elf_file: *Elf) !void {1238 pub fn updateSectionSize(copy_rel: CopyRelSection, shndx: u32, elf_file: *Elf) !void {
1244 const shdr = &elf_file.shdrs.items[shndx];1239 const shdr = &elf_file.shdrs.items[shndx];
1245 for (copy_rel.symbols.items) |sym_index| {1240 for (copy_rel.symbols.items) |ref| {
1246 const symbol = elf_file.symbol(sym_index);1241 const symbol = elf_file.symbol(ref).?;
1247 const shared_object = symbol.file(elf_file).?.shared_object;1242 const shared_object = symbol.file(elf_file).?.shared_object;
1248 const alignment = try symbol.dsoAlignment(elf_file);1243 const alignment = try symbol.dsoAlignment(elf_file);
1249 symbol.value = @intCast(mem.alignForward(u64, shdr.sh_size, alignment));1244 symbol.value = @intCast(mem.alignForward(u64, shdr.sh_size, alignment));
1250 shdr.sh_addralign = @max(shdr.sh_addralign, alignment);1245 shdr.sh_addralign = @max(shdr.sh_addralign, alignment);
1251 shdr.sh_size = @as(u64, @intCast(symbol.value)) + symbol.elfSym(elf_file).st_size;1246 shdr.sh_size = @as(u64, @intCast(symbol.value)) + symbol.elfSym(elf_file).st_size;
12521247
1253 const aliases = shared_object.symbolAliases(sym_index, elf_file);1248 const aliases = shared_object.symbolAliases(ref.index, elf_file);
1254 for (aliases) |alias| {1249 for (aliases) |alias| {
1255 if (alias == sym_index) continue;1250 if (alias == ref.index) continue;
1256 const alias_sym = elf_file.symbol(alias);1251 const alias_sym = &shared_object.symbols.items[alias];
1257 alias_sym.value = symbol.value;1252 alias_sym.value = symbol.value;
1258 }1253 }
1259 }1254 }
...@@ -1264,10 +1259,10 @@ pub const CopyRelSection = struct {...@@ -1264,10 +1259,10 @@ pub const CopyRelSection = struct {
1264 const gpa = comp.gpa;1259 const gpa = comp.gpa;
1265 const cpu_arch = elf_file.getTarget().cpu.arch;1260 const cpu_arch = elf_file.getTarget().cpu.arch;
1266 try elf_file.rela_dyn.ensureUnusedCapacity(gpa, copy_rel.numRela());1261 try elf_file.rela_dyn.ensureUnusedCapacity(gpa, copy_rel.numRela());
1267 for (copy_rel.symbols.items) |sym_index| {1262 for (copy_rel.symbols.items) |ref| {
1268 const sym = elf_file.symbol(sym_index);1263 const sym = elf_file.symbol(ref).?;
1269 assert(sym.flags.import and sym.flags.has_copy_rel);1264 assert(sym.flags.import and sym.flags.has_copy_rel);
1270 const extra = sym.extra(elf_file).?;1265 const extra = sym.extra(elf_file);
1271 elf_file.addRelaDynAssumeCapacity(.{1266 elf_file.addRelaDynAssumeCapacity(.{
1272 .offset = @intCast(sym.address(.{}, elf_file)),1267 .offset = @intCast(sym.address(.{}, elf_file)),
1273 .sym = extra.dynamic,1268 .sym = extra.dynamic,
...@@ -1285,8 +1280,8 @@ pub const DynsymSection = struct {...@@ -1285,8 +1280,8 @@ pub const DynsymSection = struct {
1285 entries: std.ArrayListUnmanaged(Entry) = .{},1280 entries: std.ArrayListUnmanaged(Entry) = .{},
12861281
1287 pub const Entry = struct {1282 pub const Entry = struct {
1288 /// Index of the symbol which gets privilege of getting a dynamic treatment1283 /// Ref of the symbol which gets privilege of getting a dynamic treatment
1289 symbol_index: Symbol.Index,1284 ref: Elf.Ref,
1290 /// Offset into .dynstrtab1285 /// Offset into .dynstrtab
1291 off: u32,1286 off: u32,
1292 };1287 };
...@@ -1295,22 +1290,22 @@ pub const DynsymSection = struct {...@@ -1295,22 +1290,22 @@ pub const DynsymSection = struct {
1295 dynsym.entries.deinit(allocator);1290 dynsym.entries.deinit(allocator);
1296 }1291 }
12971292
1298 pub fn addSymbol(dynsym: *DynsymSection, sym_index: Symbol.Index, elf_file: *Elf) !void {1293 pub fn addSymbol(dynsym: *DynsymSection, ref: Elf.Ref, elf_file: *Elf) !void {
1299 const comp = elf_file.base.comp;1294 const comp = elf_file.base.comp;
1300 const gpa = comp.gpa;1295 const gpa = comp.gpa;
1301 const index = @as(u32, @intCast(dynsym.entries.items.len + 1));1296 const index = @as(u32, @intCast(dynsym.entries.items.len + 1));
1302 const sym = elf_file.symbol(sym_index);1297 const sym = elf_file.symbol(ref).?;
1303 sym.flags.has_dynamic = true;1298 sym.flags.has_dynamic = true;
1304 try sym.addExtra(.{ .dynamic = index }, elf_file);1299 sym.addExtra(.{ .dynamic = index }, elf_file);
1305 const off = try elf_file.insertDynString(sym.name(elf_file));1300 const off = try elf_file.insertDynString(sym.name(elf_file));
1306 try dynsym.entries.append(gpa, .{ .symbol_index = sym_index, .off = off });1301 try dynsym.entries.append(gpa, .{ .ref = ref, .off = off });
1307 }1302 }
13081303
1309 pub fn sort(dynsym: *DynsymSection, elf_file: *Elf) void {1304 pub fn sort(dynsym: *DynsymSection, elf_file: *Elf) void {
1310 const Sort = struct {1305 const Sort = struct {
1311 pub fn lessThan(ctx: *Elf, lhs: Entry, rhs: Entry) bool {1306 pub fn lessThan(ctx: *Elf, lhs: Entry, rhs: Entry) bool {
1312 const lhs_sym = ctx.symbol(lhs.symbol_index);1307 const lhs_sym = ctx.symbol(lhs.ref).?;
1313 const rhs_sym = ctx.symbol(rhs.symbol_index);1308 const rhs_sym = ctx.symbol(rhs.ref).?;
13141309
1315 if (lhs_sym.flags.@"export" != rhs_sym.flags.@"export") {1310 if (lhs_sym.flags.@"export" != rhs_sym.flags.@"export") {
1316 return rhs_sym.flags.@"export";1311 return rhs_sym.flags.@"export";
...@@ -1322,14 +1317,14 @@ pub const DynsymSection = struct {...@@ -1322,14 +1317,14 @@ pub const DynsymSection = struct {
1322 const rhs_hash = GnuHashSection.hasher(rhs_sym.name(ctx)) % nbuckets;1317 const rhs_hash = GnuHashSection.hasher(rhs_sym.name(ctx)) % nbuckets;
13231318
1324 if (lhs_hash == rhs_hash)1319 if (lhs_hash == rhs_hash)
1325 return lhs_sym.extra(ctx).?.dynamic < rhs_sym.extra(ctx).?.dynamic;1320 return lhs_sym.extra(ctx).dynamic < rhs_sym.extra(ctx).dynamic;
1326 return lhs_hash < rhs_hash;1321 return lhs_hash < rhs_hash;
1327 }1322 }
1328 };1323 };
13291324
1330 var num_exports: u32 = 0;1325 var num_exports: u32 = 0;
1331 for (dynsym.entries.items) |entry| {1326 for (dynsym.entries.items) |entry| {
1332 const sym = elf_file.symbol(entry.symbol_index);1327 const sym = elf_file.symbol(entry.ref).?;
1333 if (sym.flags.@"export") num_exports += 1;1328 if (sym.flags.@"export") num_exports += 1;
1334 }1329 }
13351330
...@@ -1338,8 +1333,8 @@ pub const DynsymSection = struct {...@@ -1338,8 +1333,8 @@ pub const DynsymSection = struct {
1338 std.mem.sort(Entry, dynsym.entries.items, elf_file, Sort.lessThan);1333 std.mem.sort(Entry, dynsym.entries.items, elf_file, Sort.lessThan);
13391334
1340 for (dynsym.entries.items, 1..) |entry, index| {1335 for (dynsym.entries.items, 1..) |entry, index| {
1341 const sym = elf_file.symbol(entry.symbol_index);1336 const sym = elf_file.symbol(entry.ref).?;
1342 var extra = sym.extra(elf_file).?;1337 var extra = sym.extra(elf_file);
1343 extra.dynamic = @as(u32, @intCast(index));1338 extra.dynamic = @as(u32, @intCast(index));
1344 sym.setExtra(extra, elf_file);1339 sym.setExtra(extra, elf_file);
1345 }1340 }
...@@ -1356,7 +1351,7 @@ pub const DynsymSection = struct {...@@ -1356,7 +1351,7 @@ pub const DynsymSection = struct {
1356 pub fn write(dynsym: DynsymSection, elf_file: *Elf, writer: anytype) !void {1351 pub fn write(dynsym: DynsymSection, elf_file: *Elf, writer: anytype) !void {
1357 try writer.writeStruct(Elf.null_sym);1352 try writer.writeStruct(Elf.null_sym);
1358 for (dynsym.entries.items) |entry| {1353 for (dynsym.entries.items) |entry| {
1359 const sym = elf_file.symbol(entry.symbol_index);1354 const sym = elf_file.symbol(entry.ref).?;
1360 var out_sym: elf.Elf64_Sym = Elf.null_sym;1355 var out_sym: elf.Elf64_Sym = Elf.null_sym;
1361 sym.setOutputSym(elf_file, &out_sym);1356 sym.setOutputSym(elf_file, &out_sym);
1362 out_sym.st_name = entry.off;1357 out_sym.st_name = entry.off;
...@@ -1429,7 +1424,7 @@ pub const GnuHashSection = struct {...@@ -1429,7 +1424,7 @@ pub const GnuHashSection = struct {
14291424
1430 fn getExports(elf_file: *Elf) []const DynsymSection.Entry {1425 fn getExports(elf_file: *Elf) []const DynsymSection.Entry {
1431 const start = for (elf_file.dynsym.entries.items, 0..) |entry, i| {1426 const start = for (elf_file.dynsym.entries.items, 0..) |entry, i| {
1432 const sym = elf_file.symbol(entry.symbol_index);1427 const sym = elf_file.symbol(entry.ref).?;
1433 if (sym.flags.@"export") break i;1428 if (sym.flags.@"export") break i;
1434 } else elf_file.dynsym.entries.items.len;1429 } else elf_file.dynsym.entries.items.len;
1435 return elf_file.dynsym.entries.items[start..];1430 return elf_file.dynsym.entries.items[start..];
...@@ -1477,7 +1472,7 @@ pub const GnuHashSection = struct {...@@ -1477,7 +1472,7 @@ pub const GnuHashSection = struct {
1477 @memset(bloom, 0);1472 @memset(bloom, 0);
14781473
1479 for (exports, 0..) |entry, i| {1474 for (exports, 0..) |entry, i| {
1480 const sym = elf_file.symbol(entry.symbol_index);1475 const sym = elf_file.symbol(entry.ref).?;
1481 const h = hasher(sym.name(elf_file));1476 const h = hasher(sym.name(elf_file));
1482 hashes[i] = h;1477 hashes[i] = h;
1483 indices[i] = h % hash.num_buckets;1478 indices[i] = h % hash.num_buckets;
...@@ -1574,7 +1569,7 @@ pub const VerneedSection = struct {...@@ -1574,7 +1569,7 @@ pub const VerneedSection = struct {
1574 try verneed.ensureTotalCapacity(dynsyms.len);1569 try verneed.ensureTotalCapacity(dynsyms.len);
15751570
1576 for (dynsyms, 1..) |entry, i| {1571 for (dynsyms, 1..) |entry, i| {
1577 const symbol = elf_file.symbol(entry.symbol_index);1572 const symbol = elf_file.symbol(entry.ref).?;
1578 if (symbol.flags.import and symbol.version_index & elf.VERSYM_VERSION > elf.VER_NDX_GLOBAL) {1573 if (symbol.flags.import and symbol.version_index & elf.VERSYM_VERSION > elf.VER_NDX_GLOBAL) {
1579 const shared_object = symbol.file(elf_file).?.shared_object;1574 const shared_object = symbol.file(elf_file).?.shared_object;
1580 verneed.appendAssumeCapacity(.{1575 verneed.appendAssumeCapacity(.{
...@@ -1677,11 +1672,11 @@ pub const ComdatGroupSection = struct {...@@ -1677,11 +1672,11 @@ pub const ComdatGroupSection = struct {
1677 return cg_file.object.comdatGroup(cgs.cg_ref.index);1672 return cg_file.object.comdatGroup(cgs.cg_ref.index);
1678 }1673 }
16791674
1680 pub fn symbol(cgs: ComdatGroupSection, elf_file: *Elf) Symbol.Index {1675 pub fn symbol(cgs: ComdatGroupSection, elf_file: *Elf) *Symbol {
1681 const cg = cgs.comdatGroup(elf_file);1676 const cg = cgs.comdatGroup(elf_file);
1682 const object = cg.file(elf_file).object;1677 const object = cg.file(elf_file).object;
1683 const shdr = object.shdrs.items[cg.shndx];1678 const shdr = object.shdrs.items[cg.shndx];
1684 return object.symbols.items[shdr.sh_info];1679 return &object.symbols.items[shdr.sh_info];
1685 }1680 }
16861681
1687 pub fn size(cgs: ComdatGroupSection, elf_file: *Elf) usize {1682 pub fn size(cgs: ComdatGroupSection, elf_file: *Elf) usize {
src/link/Elf/thunks.zig+16-24
...@@ -43,11 +43,7 @@ pub fn createThunks(shndx: u32, elf_file: *Elf) !void {...@@ -43,11 +43,7 @@ pub fn createThunks(shndx: u32, elf_file: *Elf) !void {
43 else => @panic("unsupported arch"),43 else => @panic("unsupported arch"),
44 };44 };
45 if (is_reachable) continue;45 if (is_reachable) continue;
46 const target = switch (file) {46 const target = file.resolveSymbol(rel.r_sym(), elf_file);
47 .zig_object => |x| x.symbol(rel.r_sym()),
48 .object => |x| x.symbols.items[rel.r_sym()],
49 else => unreachable,
50 };
51 try thunk.symbols.put(gpa, target, {});47 try thunk.symbols.put(gpa, target, {});
52 }48 }
53 atom.addExtra(.{ .thunk = thunk_index }, elf_file);49 atom.addExtra(.{ .thunk = thunk_index }, elf_file);
...@@ -80,7 +76,7 @@ fn maxAllowedDistance(cpu_arch: std.Target.Cpu.Arch) u32 {...@@ -80,7 +76,7 @@ fn maxAllowedDistance(cpu_arch: std.Target.Cpu.Arch) u32 {
80pub const Thunk = struct {76pub const Thunk = struct {
81 value: i64 = 0,77 value: i64 = 0,
82 output_section_index: u32 = 0,78 output_section_index: u32 = 0,
83 symbols: std.AutoArrayHashMapUnmanaged(Symbol.Index, void) = .{},79 symbols: std.AutoArrayHashMapUnmanaged(Elf.Ref, void) = .{},
84 output_symtab_ctx: Elf.SymtabCtx = .{},80 output_symtab_ctx: Elf.SymtabCtx = .{},
8581
86 pub fn deinit(thunk: *Thunk, allocator: Allocator) void {82 pub fn deinit(thunk: *Thunk, allocator: Allocator) void {
...@@ -97,9 +93,9 @@ pub const Thunk = struct {...@@ -97,9 +93,9 @@ pub const Thunk = struct {
97 return @as(i64, @intCast(shdr.sh_addr)) + thunk.value;93 return @as(i64, @intCast(shdr.sh_addr)) + thunk.value;
98 }94 }
9995
100 pub fn targetAddress(thunk: Thunk, sym_index: Symbol.Index, elf_file: *Elf) i64 {96 pub fn targetAddress(thunk: Thunk, ref: Elf.Ref, elf_file: *Elf) i64 {
101 const cpu_arch = elf_file.getTarget().cpu.arch;97 const cpu_arch = elf_file.getTarget().cpu.arch;
102 return thunk.address(elf_file) + @as(i64, @intCast(thunk.symbols.getIndex(sym_index).? * trampolineSize(cpu_arch)));98 return thunk.address(elf_file) + @as(i64, @intCast(thunk.symbols.getIndex(ref).? * trampolineSize(cpu_arch)));
103 }99 }
104100
105 pub fn write(thunk: Thunk, elf_file: *Elf, writer: anytype) !void {101 pub fn write(thunk: Thunk, elf_file: *Elf, writer: anytype) !void {
...@@ -112,16 +108,16 @@ pub const Thunk = struct {...@@ -112,16 +108,16 @@ pub const Thunk = struct {
112108
113 pub fn calcSymtabSize(thunk: *Thunk, elf_file: *Elf) void {109 pub fn calcSymtabSize(thunk: *Thunk, elf_file: *Elf) void {
114 thunk.output_symtab_ctx.nlocals = @as(u32, @intCast(thunk.symbols.keys().len));110 thunk.output_symtab_ctx.nlocals = @as(u32, @intCast(thunk.symbols.keys().len));
115 for (thunk.symbols.keys()) |sym_index| {111 for (thunk.symbols.keys()) |ref| {
116 const sym = elf_file.symbol(sym_index);112 const sym = elf_file.symbol(ref).?;
117 thunk.output_symtab_ctx.strsize += @as(u32, @intCast(sym.name(elf_file).len + "$thunk".len + 1));113 thunk.output_symtab_ctx.strsize += @as(u32, @intCast(sym.name(elf_file).len + "$thunk".len + 1));
118 }114 }
119 }115 }
120116
121 pub fn writeSymtab(thunk: Thunk, elf_file: *Elf) void {117 pub fn writeSymtab(thunk: Thunk, elf_file: *Elf) void {
122 const cpu_arch = elf_file.getTarget().cpu.arch;118 const cpu_arch = elf_file.getTarget().cpu.arch;
123 for (thunk.symbols.keys(), thunk.output_symtab_ctx.ilocal..) |sym_index, ilocal| {119 for (thunk.symbols.keys(), thunk.output_symtab_ctx.ilocal..) |ref, ilocal| {
124 const sym = elf_file.symbol(sym_index);120 const sym = elf_file.symbol(ref).?;
125 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));121 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
126 elf_file.strtab.appendSliceAssumeCapacity(sym.name(elf_file));122 elf_file.strtab.appendSliceAssumeCapacity(sym.name(elf_file));
127 elf_file.strtab.appendSliceAssumeCapacity("$thunk");123 elf_file.strtab.appendSliceAssumeCapacity("$thunk");
...@@ -131,7 +127,7 @@ pub const Thunk = struct {...@@ -131,7 +127,7 @@ pub const Thunk = struct {
131 .st_info = elf.STT_FUNC,127 .st_info = elf.STT_FUNC,
132 .st_other = 0,128 .st_other = 0,
133 .st_shndx = @intCast(thunk.output_section_index),129 .st_shndx = @intCast(thunk.output_section_index),
134 .st_value = @intCast(thunk.targetAddress(sym_index, elf_file)),130 .st_value = @intCast(thunk.targetAddress(ref, elf_file)),
135 .st_size = trampolineSize(cpu_arch),131 .st_size = trampolineSize(cpu_arch),
136 };132 };
137 }133 }
...@@ -181,9 +177,9 @@ pub const Thunk = struct {...@@ -181,9 +177,9 @@ pub const Thunk = struct {
181 const thunk = ctx.thunk;177 const thunk = ctx.thunk;
182 const elf_file = ctx.elf_file;178 const elf_file = ctx.elf_file;
183 try writer.print("@{x} : size({x})\n", .{ thunk.value, thunk.size(elf_file) });179 try writer.print("@{x} : size({x})\n", .{ thunk.value, thunk.size(elf_file) });
184 for (thunk.symbols.keys()) |index| {180 for (thunk.symbols.keys()) |ref| {
185 const sym = elf_file.symbol(index);181 const sym = elf_file.symbol(ref).?;
186 try writer.print(" %{d} : {s} : @{x}\n", .{ index, sym.name(elf_file), sym.value });182 try writer.print(" {} : {s} : @{x}\n", .{ ref, sym.name(elf_file), sym.value });
187 }183 }
188 }184 }
189185
...@@ -195,12 +191,8 @@ const aarch64 = struct {...@@ -195,12 +191,8 @@ const aarch64 = struct {
195 const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_type());191 const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_type());
196 if (r_type != .CALL26 and r_type != .JUMP26) return true;192 if (r_type != .CALL26 and r_type != .JUMP26) return true;
197 const file = atom.file(elf_file).?;193 const file = atom.file(elf_file).?;
198 const target_index = switch (file) {194 const target_ref = file.resolveSymbol(rel.r_sym(), elf_file);
199 .zig_object => |x| x.symbol(rel.r_sym()),195 const target = elf_file.symbol(target_ref).?;
200 .object => |x| x.symbols.items[rel.r_sym()],
201 else => unreachable,
202 };
203 const target = elf_file.symbol(target_index);
204 if (target.flags.has_plt) return false;196 if (target.flags.has_plt) return false;
205 if (atom.output_section_index != target.output_section_index) return false;197 if (atom.output_section_index != target.output_section_index) return false;
206 const target_atom = target.atom(elf_file).?;198 const target_atom = target.atom(elf_file).?;
...@@ -212,8 +204,8 @@ const aarch64 = struct {...@@ -212,8 +204,8 @@ const aarch64 = struct {
212 }204 }
213205
214 fn write(thunk: Thunk, elf_file: *Elf, writer: anytype) !void {206 fn write(thunk: Thunk, elf_file: *Elf, writer: anytype) !void {
215 for (thunk.symbols.keys(), 0..) |sym_index, i| {207 for (thunk.symbols.keys(), 0..) |ref, i| {
216 const sym = elf_file.symbol(sym_index);208 const sym = elf_file.symbol(ref).?;
217 const saddr = thunk.address(elf_file) + @as(i64, @intCast(i * trampoline_size));209 const saddr = thunk.address(elf_file) + @as(i64, @intCast(i * trampoline_size));
218 const taddr = sym.address(.{}, elf_file);210 const taddr = sym.address(.{}, elf_file);
219 const pages = try util.calcNumberOfPages(saddr, taddr);211 const pages = try util.calcNumberOfPages(saddr, taddr);