authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-04-18 14:04:42+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-04-21 22:44:25+02:00
log8a3ad3f6204747b5621e14cae0564ee7929a7cd8
tree349b9386d0acd3f5314ec58482f5b3d14bf2baee
parent528b66f6ec9cfb140abff3dc0c4735c179520f42

elf: do not reserve a GOT slot for every Atom


8 files changed, 132 insertions(+), 53 deletions(-)

src/arch/aarch64/CodeGen.zig+1
...@@ -4290,6 +4290,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -4290,6 +4290,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
4290 if (self.bin_file.cast(link.File.Elf)) |elf_file| {4290 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
4291 const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl);4291 const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl);
4292 const atom = elf_file.getAtom(atom_index);4292 const atom = elf_file.getAtom(atom_index);
4293 _ = try atom.getOrCreateOffsetTableEntry(elf_file);
4293 const got_addr = @intCast(u32, atom.getOffsetTableAddress(elf_file));4294 const got_addr = @intCast(u32, atom.getOffsetTableAddress(elf_file));
4294 try self.genSetReg(Type.initTag(.usize), .x30, .{ .memory = got_addr });4295 try self.genSetReg(Type.initTag(.usize), .x30, .{ .memory = got_addr });
4295 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {4296 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
src/arch/arm/CodeGen.zig+1
...@@ -4270,6 +4270,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -4270,6 +4270,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
4270 if (self.bin_file.cast(link.File.Elf)) |elf_file| {4270 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
4271 const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl);4271 const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl);
4272 const atom = elf_file.getAtom(atom_index);4272 const atom = elf_file.getAtom(atom_index);
4273 _ = try atom.getOrCreateOffsetTableEntry(elf_file);
4273 const got_addr = @intCast(u32, atom.getOffsetTableAddress(elf_file));4274 const got_addr = @intCast(u32, atom.getOffsetTableAddress(elf_file));
4274 try self.genSetReg(Type.initTag(.usize), .lr, .{ .memory = got_addr });4275 try self.genSetReg(Type.initTag(.usize), .lr, .{ .memory = got_addr });
4275 } else if (self.bin_file.cast(link.File.MachO)) |_| {4276 } else if (self.bin_file.cast(link.File.MachO)) |_| {
src/arch/riscv64/CodeGen.zig+1
...@@ -1734,6 +1734,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -1734,6 +1734,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
1734 const func = func_payload.data;1734 const func = func_payload.data;
1735 const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl);1735 const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl);
1736 const atom = elf_file.getAtom(atom_index);1736 const atom = elf_file.getAtom(atom_index);
1737 _ = try atom.getOrCreateOffsetTableEntry(elf_file);
1737 const got_addr = @intCast(u32, atom.getOffsetTableAddress(elf_file));1738 const got_addr = @intCast(u32, atom.getOffsetTableAddress(elf_file));
1738 try self.genSetReg(Type.initTag(.usize), .ra, .{ .memory = got_addr });1739 try self.genSetReg(Type.initTag(.usize), .ra, .{ .memory = got_addr });
1739 _ = try self.addInst(.{1740 _ = try self.addInst(.{
src/arch/sparc64/CodeGen.zig+1
...@@ -1254,6 +1254,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -1254,6 +1254,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
1254 const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: {1254 const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: {
1255 const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl);1255 const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl);
1256 const atom = elf_file.getAtom(atom_index);1256 const atom = elf_file.getAtom(atom_index);
1257 _ = try atom.getOrCreateOffsetTableEntry(elf_file);
1257 break :blk @intCast(u32, atom.getOffsetTableAddress(elf_file));1258 break :blk @intCast(u32, atom.getOffsetTableAddress(elf_file));
1258 } else unreachable;1259 } else unreachable;
12591260
src/arch/x86_64/CodeGen.zig+9-3
...@@ -5624,7 +5624,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -5624,7 +5624,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
56245624
5625 if (self.bin_file.cast(link.File.Elf)) |elf_file| {5625 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
5626 const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl);5626 const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl);
5627 const got_addr = elf_file.getAtom(atom_index).getOffsetTableAddress(elf_file);5627 const atom = elf_file.getAtom(atom_index);
5628 _ = try atom.getOrCreateOffsetTableEntry(elf_file);
5629 const got_addr = atom.getOffsetTableAddress(elf_file);
5628 try self.asmMemory(.call, Memory.sib(.qword, .{5630 try self.asmMemory(.call, Memory.sib(.qword, .{
5629 .base = .ds,5631 .base = .ds,
5630 .disp = @intCast(i32, got_addr),5632 .disp = @intCast(i32, got_addr),
...@@ -5853,7 +5855,9 @@ fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void {...@@ -5853,7 +5855,9 @@ fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void {
5853 .{ .kind = .const_data, .ty = Type.anyerror },5855 .{ .kind = .const_data, .ty = Type.anyerror },
5854 4, // dword alignment5856 4, // dword alignment
5855 );5857 );
5856 const got_addr = elf_file.getAtom(atom_index).getOffsetTableAddress(elf_file);5858 const atom = elf_file.getAtom(atom_index);
5859 _ = try atom.getOrCreateOffsetTableEntry(elf_file);
5860 const got_addr = atom.getOffsetTableAddress(elf_file);
5857 try self.asmRegisterMemory(.mov, addr_reg.to64(), Memory.sib(.qword, .{5861 try self.asmRegisterMemory(.mov, addr_reg.to64(), Memory.sib(.qword, .{
5858 .base = .ds,5862 .base = .ds,
5859 .disp = @intCast(i32, got_addr),5863 .disp = @intCast(i32, got_addr),
...@@ -8230,7 +8234,9 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {...@@ -8230,7 +8234,9 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {
8230 .{ .kind = .const_data, .ty = Type.anyerror },8234 .{ .kind = .const_data, .ty = Type.anyerror },
8231 4, // dword alignment8235 4, // dword alignment
8232 );8236 );
8233 const got_addr = elf_file.getAtom(atom_index).getOffsetTableAddress(elf_file);8237 const atom = elf_file.getAtom(atom_index);
8238 _ = try atom.getOrCreateOffsetTableEntry(elf_file);
8239 const got_addr = atom.getOffsetTableAddress(elf_file);
8234 try self.asmRegisterMemory(.mov, addr_reg.to64(), Memory.sib(.qword, .{8240 try self.asmRegisterMemory(.mov, addr_reg.to64(), Memory.sib(.qword, .{
8235 .base = .ds,8241 .base = .ds,
8236 .disp = @intCast(i32, got_addr),8242 .disp = @intCast(i32, got_addr),
src/codegen.zig+1
...@@ -1006,6 +1006,7 @@ fn genDeclRef(...@@ -1006,6 +1006,7 @@ fn genDeclRef(
1006 if (bin_file.cast(link.File.Elf)) |elf_file| {1006 if (bin_file.cast(link.File.Elf)) |elf_file| {
1007 const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index);1007 const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index);
1008 const atom = elf_file.getAtom(atom_index);1008 const atom = elf_file.getAtom(atom_index);
1009 _ = try atom.getOrCreateOffsetTableEntry(elf_file);
1009 return GenResult.mcv(.{ .memory = atom.getOffsetTableAddress(elf_file) });1010 return GenResult.mcv(.{ .memory = atom.getOffsetTableAddress(elf_file) });
1010 } else if (bin_file.cast(link.File.MachO)) |macho_file| {1011 } else if (bin_file.cast(link.File.MachO)) |macho_file| {
1011 const atom_index = try macho_file.getOrCreateAtomForDecl(decl_index);1012 const atom_index = try macho_file.getOrCreateAtomForDecl(decl_index);
src/link/Elf.zig+105-45
...@@ -63,6 +63,88 @@ const Section = struct {...@@ -63,6 +63,88 @@ const Section = struct {
63 free_list: std.ArrayListUnmanaged(Atom.Index) = .{},63 free_list: std.ArrayListUnmanaged(Atom.Index) = .{},
64};64};
6565
66const SectionTable = struct {
67 entries: std.ArrayListUnmanaged(SymIndex) = .{},
68 free_list: std.ArrayListUnmanaged(Index) = .{},
69 lookup: std.AutoHashMapUnmanaged(SymIndex, Index) = .{},
70
71 const SymIndex = u32;
72 const Index = u32;
73
74 pub fn deinit(st: *ST, allocator: Allocator) void {
75 st.entries.deinit(allocator);
76 st.free_list.deinit(allocator);
77 st.lookup.deinit(allocator);
78 }
79
80 pub fn allocateEntry(st: *ST, allocator: Allocator, target: SymIndex) !Index {
81 try st.entries.ensureUnusedCapacity(allocator, 1);
82 const index = blk: {
83 if (st.free_list.popOrNull()) |index| {
84 log.debug(" (reusing entry index {d})", .{index});
85 break :blk index;
86 } else {
87 log.debug(" (allocating entry at index {d})", .{st.entries.items.len});
88 const index = @intCast(u32, st.entries.items.len);
89 _ = st.entries.addOneAssumeCapacity();
90 break :blk index;
91 }
92 };
93 st.entries.items[index] = target;
94 try st.lookup.putNoClobber(allocator, target, index);
95 return index;
96 }
97
98 pub fn freeEntry(st: *ST, allocator: Allocator, target: SymIndex) void {
99 const index = st.lookup.get(target) orelse return;
100 st.free_list.append(allocator, index) catch {};
101 st.entries.items[index] = 0;
102 _ = st.lookup.remove(target);
103 }
104
105 const FormatContext = struct {
106 ctx: *Elf,
107 st: *const ST,
108 };
109
110 fn fmt(
111 ctx: FormatContext,
112 comptime unused_format_string: []const u8,
113 options: std.fmt.FormatOptions,
114 writer: anytype,
115 ) @TypeOf(writer).Error!void {
116 _ = options;
117 comptime assert(unused_format_string.len == 0);
118
119 const base_addr = ctx.ctx.program_headers.items[ctx.ctx.phdr_got_index.?].p_vaddr;
120 const target = ctx.ctx.base.options.target;
121 const ptr_bits = target.cpu.arch.ptrBitWidth();
122 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
123
124 try writer.writeAll("SectionTable:\n");
125 for (ctx.st.entries.items, 0..) |entry, i| {
126 try writer.print(" {d}@{x} => local(%{d})\n", .{ i, base_addr + i * ptr_bytes, entry });
127 }
128 }
129
130 fn format(st: ST, comptime unused_format_string: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
131 _ = st;
132 _ = unused_format_string;
133 _ = options;
134 _ = writer;
135 @compileError("do not format SectionTable directly; use st.fmtDebug()");
136 }
137
138 pub fn fmtDebug(st: ST, ctx: *Elf) std.fmt.Formatter(fmt) {
139 return .{ .data = .{
140 .ctx = ctx,
141 .st = st,
142 } };
143 }
144
145 const ST = @This();
146};
147
66const LazySymbolMetadata = struct {148const LazySymbolMetadata = struct {
67 text_atom: ?Atom.Index = null,149 text_atom: ?Atom.Index = null,
68 rodata_atom: ?Atom.Index = null,150 rodata_atom: ?Atom.Index = null,
...@@ -148,17 +230,13 @@ global_symbols: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},...@@ -148,17 +230,13 @@ global_symbols: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
148230
149local_symbol_free_list: std.ArrayListUnmanaged(u32) = .{},231local_symbol_free_list: std.ArrayListUnmanaged(u32) = .{},
150global_symbol_free_list: std.ArrayListUnmanaged(u32) = .{},232global_symbol_free_list: std.ArrayListUnmanaged(u32) = .{},
151offset_table_free_list: std.ArrayListUnmanaged(u32) = .{},
152233
153/// Same order as in the file. The value is the absolute vaddr value.234got_table: SectionTable = .{},
154/// If the vaddr of the executable program header changes, the entire
155/// offset table needs to be rewritten.
156offset_table: std.ArrayListUnmanaged(u64) = .{},
157235
158phdr_table_dirty: bool = false,236phdr_table_dirty: bool = false,
159shdr_table_dirty: bool = false,237shdr_table_dirty: bool = false,
160shstrtab_dirty: bool = false,238shstrtab_dirty: bool = false,
161offset_table_count_dirty: bool = false,239got_table_count_dirty: bool = false,
162240
163debug_strtab_dirty: bool = false,241debug_strtab_dirty: bool = false,
164debug_abbrev_section_dirty: bool = false,242debug_abbrev_section_dirty: bool = false,
...@@ -329,8 +407,7 @@ pub fn deinit(self: *Elf) void {...@@ -329,8 +407,7 @@ pub fn deinit(self: *Elf) void {
329 self.global_symbols.deinit(gpa);407 self.global_symbols.deinit(gpa);
330 self.global_symbol_free_list.deinit(gpa);408 self.global_symbol_free_list.deinit(gpa);
331 self.local_symbol_free_list.deinit(gpa);409 self.local_symbol_free_list.deinit(gpa);
332 self.offset_table_free_list.deinit(gpa);410 self.got_table.deinit(gpa);
333 self.offset_table.deinit(gpa);
334411
335 {412 {
336 var it = self.decls.iterator();413 var it = self.decls.iterator();
...@@ -1289,6 +1366,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1289,6 +1366,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1289 assert(!self.shdr_table_dirty);1366 assert(!self.shdr_table_dirty);
1290 assert(!self.shstrtab_dirty);1367 assert(!self.shstrtab_dirty);
1291 assert(!self.debug_strtab_dirty);1368 assert(!self.debug_strtab_dirty);
1369 assert(!self.got_table_count_dirty);
1292}1370}
12931371
1294fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !void {1372fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !void {
...@@ -2168,7 +2246,7 @@ fn freeAtom(self: *Elf, atom_index: Atom.Index) void {...@@ -2168,7 +2246,7 @@ fn freeAtom(self: *Elf, atom_index: Atom.Index) void {
2168 _ = self.atom_by_index_table.remove(local_sym_index);2246 _ = self.atom_by_index_table.remove(local_sym_index);
2169 self.getAtomPtr(atom_index).local_sym_index = 0;2247 self.getAtomPtr(atom_index).local_sym_index = 0;
21702248
2171 self.offset_table_free_list.append(self.base.allocator, atom.offset_table_index) catch {};2249 self.got_table.freeEntry(gpa, local_sym_index);
2172}2250}
21732251
2174fn shrinkAtom(self: *Elf, atom_index: Atom.Index, new_block_size: u64) void {2252fn shrinkAtom(self: *Elf, atom_index: Atom.Index, new_block_size: u64) void {
...@@ -2191,11 +2269,9 @@ pub fn createAtom(self: *Elf) !Atom.Index {...@@ -2191,11 +2269,9 @@ pub fn createAtom(self: *Elf) !Atom.Index {
2191 const atom_index = @intCast(Atom.Index, self.atoms.items.len);2269 const atom_index = @intCast(Atom.Index, self.atoms.items.len);
2192 const atom = try self.atoms.addOne(gpa);2270 const atom = try self.atoms.addOne(gpa);
2193 const local_sym_index = try self.allocateLocalSymbol();2271 const local_sym_index = try self.allocateLocalSymbol();
2194 const offset_table_index = try self.allocateGotOffset();
2195 try self.atom_by_index_table.putNoClobber(gpa, local_sym_index, atom_index);2272 try self.atom_by_index_table.putNoClobber(gpa, local_sym_index, atom_index);
2196 atom.* = .{2273 atom.* = .{
2197 .local_sym_index = local_sym_index,2274 .local_sym_index = local_sym_index,
2198 .offset_table_index = offset_table_index,
2199 .prev_index = null,2275 .prev_index = null,
2200 .next_index = null,2276 .next_index = null,
2201 };2277 };
...@@ -2352,26 +2428,6 @@ pub fn allocateLocalSymbol(self: *Elf) !u32 {...@@ -2352,26 +2428,6 @@ pub fn allocateLocalSymbol(self: *Elf) !u32 {
2352 return index;2428 return index;
2353}2429}
23542430
2355pub fn allocateGotOffset(self: *Elf) !u32 {
2356 try self.offset_table.ensureUnusedCapacity(self.base.allocator, 1);
2357
2358 const index = blk: {
2359 if (self.offset_table_free_list.popOrNull()) |index| {
2360 log.debug(" (reusing GOT offset at index {d})", .{index});
2361 break :blk index;
2362 } else {
2363 log.debug(" (allocating GOT offset at index {d})", .{self.offset_table.items.len});
2364 const index = @intCast(u32, self.offset_table.items.len);
2365 _ = self.offset_table.addOneAssumeCapacity();
2366 self.offset_table_count_dirty = true;
2367 break :blk index;
2368 }
2369 };
2370
2371 self.offset_table.items[index] = 0;
2372 return index;
2373}
2374
2375fn freeUnnamedConsts(self: *Elf, decl_index: Module.Decl.Index) void {2431fn freeUnnamedConsts(self: *Elf, decl_index: Module.Decl.Index) void {
2376 const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return;2432 const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return;
2377 for (unnamed_consts.items) |atom| {2433 for (unnamed_consts.items) |atom| {
...@@ -2465,6 +2521,7 @@ fn updateDeclCode(self: *Elf, decl_index: Module.Decl.Index, code: []const u8, s...@@ -2465,6 +2521,7 @@ fn updateDeclCode(self: *Elf, decl_index: Module.Decl.Index, code: []const u8, s
2465 const decl_metadata = self.decls.get(decl_index).?;2521 const decl_metadata = self.decls.get(decl_index).?;
2466 const atom_index = decl_metadata.atom;2522 const atom_index = decl_metadata.atom;
2467 const atom = self.getAtom(atom_index);2523 const atom = self.getAtom(atom_index);
2524 const local_sym_index = atom.getSymbolIndex().?;
24682525
2469 const shdr_index = decl_metadata.shdr;2526 const shdr_index = decl_metadata.shdr;
2470 if (atom.getSymbol(self).st_size != 0 and self.base.child_pid == null) {2527 if (atom.getSymbol(self).st_size != 0 and self.base.child_pid == null) {
...@@ -2485,8 +2542,9 @@ fn updateDeclCode(self: *Elf, decl_index: Module.Decl.Index, code: []const u8, s...@@ -2485,8 +2542,9 @@ fn updateDeclCode(self: *Elf, decl_index: Module.Decl.Index, code: []const u8, s
2485 local_sym.st_value = vaddr;2542 local_sym.st_value = vaddr;
24862543
2487 log.debug(" (writing new offset table entry)", .{});2544 log.debug(" (writing new offset table entry)", .{});
2488 self.offset_table.items[atom.offset_table_index] = vaddr;2545 const got_entry_index = self.got_table.lookup.get(local_sym_index).?;
2489 try self.writeOffsetTableEntry(atom.offset_table_index);2546 self.got_table.entries.items[got_entry_index] = local_sym_index;
2547 try self.writeOffsetTableEntry(got_entry_index);
2490 }2548 }
2491 } else if (code.len < local_sym.st_size) {2549 } else if (code.len < local_sym.st_size) {
2492 self.shrinkAtom(atom_index, code.len);2550 self.shrinkAtom(atom_index, code.len);
...@@ -2494,7 +2552,7 @@ fn updateDeclCode(self: *Elf, decl_index: Module.Decl.Index, code: []const u8, s...@@ -2494,7 +2552,7 @@ fn updateDeclCode(self: *Elf, decl_index: Module.Decl.Index, code: []const u8, s
2494 local_sym.st_size = code.len;2552 local_sym.st_size = code.len;
24952553
2496 // TODO this write could be avoided if no fields of the symbol were changed.2554 // TODO this write could be avoided if no fields of the symbol were changed.
2497 try self.writeSymbol(atom.getSymbolIndex().?);2555 try self.writeSymbol(local_sym_index);
2498 } else {2556 } else {
2499 const local_sym = atom.getSymbolPtr(self);2557 const local_sym = atom.getSymbolPtr(self);
2500 local_sym.* = .{2558 local_sym.* = .{
...@@ -2509,12 +2567,12 @@ fn updateDeclCode(self: *Elf, decl_index: Module.Decl.Index, code: []const u8, s...@@ -2509,12 +2567,12 @@ fn updateDeclCode(self: *Elf, decl_index: Module.Decl.Index, code: []const u8, s
2509 errdefer self.freeAtom(atom_index);2567 errdefer self.freeAtom(atom_index);
2510 log.debug("allocated text block for {s} at 0x{x}", .{ decl_name, vaddr });2568 log.debug("allocated text block for {s} at 0x{x}", .{ decl_name, vaddr });
25112569
2512 self.offset_table.items[atom.offset_table_index] = vaddr;
2513 local_sym.st_value = vaddr;2570 local_sym.st_value = vaddr;
2514 local_sym.st_size = code.len;2571 local_sym.st_size = code.len;
25152572
2516 try self.writeSymbol(atom.getSymbolIndex().?);2573 try self.writeSymbol(local_sym_index);
2517 try self.writeOffsetTableEntry(atom.offset_table_index);2574 const got_entry_index = try atom.getOrCreateOffsetTableEntry(self);
2575 try self.writeOffsetTableEntry(got_entry_index);
2518 }2576 }
25192577
2520 const local_sym = atom.getSymbolPtr(self);2578 const local_sym = atom.getSymbolPtr(self);
...@@ -2755,12 +2813,12 @@ fn updateLazySymbolAtom(...@@ -2755,12 +2813,12 @@ fn updateLazySymbolAtom(
2755 errdefer self.freeAtom(atom_index);2813 errdefer self.freeAtom(atom_index);
2756 log.debug("allocated text block for {s} at 0x{x}", .{ name, vaddr });2814 log.debug("allocated text block for {s} at 0x{x}", .{ name, vaddr });
27572815
2758 self.offset_table.items[atom.offset_table_index] = vaddr;
2759 local_sym.st_value = vaddr;2816 local_sym.st_value = vaddr;
2760 local_sym.st_size = code.len;2817 local_sym.st_size = code.len;
27612818
2762 try self.writeSymbol(local_sym_index);2819 try self.writeSymbol(local_sym_index);
2763 try self.writeOffsetTableEntry(atom.offset_table_index);2820 const got_entry_index = try atom.getOrCreateOffsetTableEntry(self);
2821 try self.writeOffsetTableEntry(got_entry_index);
27642822
2765 const section_offset = vaddr - self.program_headers.items[phdr_index].p_vaddr;2823 const section_offset = vaddr - self.program_headers.items[phdr_index].p_vaddr;
2766 const file_offset = self.sections.items(.shdr)[shdr_index].sh_offset + section_offset;2824 const file_offset = self.sections.items(.shdr)[shdr_index].sh_offset + section_offset;
...@@ -2991,30 +3049,32 @@ fn writeSectHeader(self: *Elf, index: usize) !void {...@@ -2991,30 +3049,32 @@ fn writeSectHeader(self: *Elf, index: usize) !void {
29913049
2992fn writeOffsetTableEntry(self: *Elf, index: usize) !void {3050fn writeOffsetTableEntry(self: *Elf, index: usize) !void {
2993 const entry_size: u16 = self.archPtrWidthBytes();3051 const entry_size: u16 = self.archPtrWidthBytes();
2994 if (self.offset_table_count_dirty) {3052 if (self.got_table_count_dirty) {
2995 const needed_size = self.offset_table.items.len * entry_size;3053 const needed_size = self.got_table.entries.items.len * entry_size;
2996 try self.growAllocSection(self.got_section_index.?, needed_size);3054 try self.growAllocSection(self.got_section_index.?, needed_size);
2997 self.offset_table_count_dirty = false;3055 self.got_table_count_dirty = false;
2998 }3056 }
2999 const endian = self.base.options.target.cpu.arch.endian();3057 const endian = self.base.options.target.cpu.arch.endian();
3000 const shdr = &self.sections.items(.shdr)[self.got_section_index.?];3058 const shdr = &self.sections.items(.shdr)[self.got_section_index.?];
3001 const off = shdr.sh_offset + @as(u64, entry_size) * index;3059 const off = shdr.sh_offset + @as(u64, entry_size) * index;
3002 const phdr = &self.program_headers.items[self.phdr_got_index.?];3060 const phdr = &self.program_headers.items[self.phdr_got_index.?];
3003 const vaddr = phdr.p_vaddr + @as(u64, entry_size) * index;3061 const vaddr = phdr.p_vaddr + @as(u64, entry_size) * index;
3062 const got_entry = self.got_table.entries.items[index];
3063 const got_value = self.getSymbol(got_entry).st_value;
3004 switch (entry_size) {3064 switch (entry_size) {
3005 2 => {3065 2 => {
3006 var buf: [2]u8 = undefined;3066 var buf: [2]u8 = undefined;
3007 mem.writeInt(u16, &buf, @intCast(u16, self.offset_table.items[index]), endian);3067 mem.writeInt(u16, &buf, @intCast(u16, got_value), endian);
3008 try self.base.file.?.pwriteAll(&buf, off);3068 try self.base.file.?.pwriteAll(&buf, off);
3009 },3069 },
3010 4 => {3070 4 => {
3011 var buf: [4]u8 = undefined;3071 var buf: [4]u8 = undefined;
3012 mem.writeInt(u32, &buf, @intCast(u32, self.offset_table.items[index]), endian);3072 mem.writeInt(u32, &buf, @intCast(u32, got_value), endian);
3013 try self.base.file.?.pwriteAll(&buf, off);3073 try self.base.file.?.pwriteAll(&buf, off);
3014 },3074 },
3015 8 => {3075 8 => {
3016 var buf: [8]u8 = undefined;3076 var buf: [8]u8 = undefined;
3017 mem.writeInt(u64, &buf, self.offset_table.items[index], endian);3077 mem.writeInt(u64, &buf, got_value, endian);
3018 try self.base.file.?.pwriteAll(&buf, off);3078 try self.base.file.?.pwriteAll(&buf, off);
30193079
3020 if (self.base.child_pid) |pid| {3080 if (self.base.child_pid) |pid| {
src/link/Elf/Atom.zig+13-5
...@@ -14,9 +14,6 @@ const Elf = @import("../Elf.zig");...@@ -14,9 +14,6 @@ const Elf = @import("../Elf.zig");
14/// offset table entry.14/// offset table entry.
15local_sym_index: u32,15local_sym_index: u32,
1616
17/// This field is undefined for symbols with size = 0.
18offset_table_index: u32,
19
20/// Points to the previous and next neighbors, based on the `text_offset`.17/// Points to the previous and next neighbors, based on the `text_offset`.
21/// This can be used to find, for example, the capacity of this `TextBlock`.18/// This can be used to find, for example, the capacity of this `TextBlock`.
22prev_index: ?Index,19prev_index: ?Index,
...@@ -48,13 +45,24 @@ pub fn getName(self: Atom, elf_file: *const Elf) []const u8 {...@@ -48,13 +45,24 @@ pub fn getName(self: Atom, elf_file: *const Elf) []const u8 {
48 return elf_file.getSymbolName(self.getSymbolIndex().?);45 return elf_file.getSymbolName(self.getSymbolIndex().?);
49}46}
5047
48/// If entry already exists, returns index to it.
49/// Otherwise, creates a new entry in the Global Offset Table for this Atom.
50pub fn getOrCreateOffsetTableEntry(self: Atom, elf_file: *Elf) !u32 {
51 const sym_index = self.getSymbolIndex().?;
52 if (elf_file.got_table.lookup.get(sym_index)) |index| return index;
53 const index = try elf_file.got_table.allocateEntry(elf_file.base.allocator, sym_index);
54 elf_file.got_table_count_dirty = true;
55 return index;
56}
57
51pub fn getOffsetTableAddress(self: Atom, elf_file: *Elf) u64 {58pub fn getOffsetTableAddress(self: Atom, elf_file: *Elf) u64 {
52 assert(self.getSymbolIndex() != null);59 const sym_index = self.getSymbolIndex().?;
60 const got_entry_index = elf_file.got_table.lookup.get(sym_index).?;
53 const target = elf_file.base.options.target;61 const target = elf_file.base.options.target;
54 const ptr_bits = target.cpu.arch.ptrBitWidth();62 const ptr_bits = target.cpu.arch.ptrBitWidth();
55 const ptr_bytes: u64 = @divExact(ptr_bits, 8);63 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
56 const got = elf_file.program_headers.items[elf_file.phdr_got_index.?];64 const got = elf_file.program_headers.items[elf_file.phdr_got_index.?];
57 return got.p_vaddr + self.offset_table_index * ptr_bytes;65 return got.p_vaddr + got_entry_index * ptr_bytes;
58}66}
5967
60/// Returns how much room there is to grow in virtual address space.68/// Returns how much room there is to grow in virtual address space.