authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-09-10 22:46:59+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-09-11 07:59:54+02:00
logd07edfabd6e45a486d1611e357887d01b38db32e
treef65dfcc372dddb4ccaf649ca4d22f582f7f5bcf2
parent4b082d89c9cd6e40259701f21344d55eef2a8d2e

elf: simplify handling of relocs for atoms


4 files changed, 82 insertions(+), 75 deletions(-)

src/link/Elf.zig+7-49
...@@ -135,10 +135,6 @@ last_atom_and_free_list_table: std.AutoArrayHashMapUnmanaged(u16, LastAtomAndFre...@@ -135,10 +135,6 @@ last_atom_and_free_list_table: std.AutoArrayHashMapUnmanaged(u16, LastAtomAndFre
135/// with `Decl` `main`, and lives as long as that `Decl`.135/// with `Decl` `main`, and lives as long as that `Decl`.
136unnamed_consts: UnnamedConstTable = .{},136unnamed_consts: UnnamedConstTable = .{},
137137
138/// A table of relocations indexed by the owning them `TextBlock`.
139relocs: RelocTable = .{},
140
141const RelocTable = std.AutoHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Atom.Reloc));
142const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Symbol.Index));138const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Symbol.Index));
143const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata);139const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata);
144140
...@@ -293,14 +289,6 @@ pub fn deinit(self: *Elf) void {...@@ -293,14 +289,6 @@ pub fn deinit(self: *Elf) void {
293 self.unnamed_consts.deinit(gpa);289 self.unnamed_consts.deinit(gpa);
294 }290 }
295291
296 {
297 var it = self.relocs.valueIterator();
298 while (it.next()) |relocs| {
299 relocs.deinit(gpa);
300 }
301 self.relocs.deinit(gpa);
302 }
303
304 if (self.dwarf) |*dw| {292 if (self.dwarf) |*dw| {
305 dw.deinit();293 dw.deinit();
306 }294 }
...@@ -312,12 +300,11 @@ pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: link....@@ -312,12 +300,11 @@ pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: link.
312 const this_sym_index = try self.getOrCreateMetadataForDecl(decl_index);300 const this_sym_index = try self.getOrCreateMetadataForDecl(decl_index);
313 const this_sym = self.symbol(this_sym_index);301 const this_sym = self.symbol(this_sym_index);
314 const vaddr = this_sym.value;302 const vaddr = this_sym.value;
315 const parent_atom_index = self.symbol(reloc_info.parent_atom_index).atom_index;303 const parent_atom = self.symbol(reloc_info.parent_atom_index).atom(self).?;
316 try Atom.addRelocation(self, parent_atom_index, .{304 try parent_atom.addReloc(self, .{
317 .target = this_sym_index,305 .target = this_sym_index,
318 .offset = reloc_info.offset,306 .offset = reloc_info.offset,
319 .addend = reloc_info.addend,307 .addend = reloc_info.addend,
320 .prev_vaddr = vaddr,
321 });308 });
322309
323 return vaddr;310 return vaddr;
...@@ -1032,38 +1019,9 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1032,38 +1019,9 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
10321019
1033 // Beyond this point, everything has been allocated a virtual address and we can resolve1020 // Beyond this point, everything has been allocated a virtual address and we can resolve
1034 // the relocations.1021 // the relocations.
1035 {1022 if (self.zig_module_index) |index| {
1036 var it = self.relocs.iterator();1023 for (self.file(index).?.zig_module.atoms.items) |atom_index| {
1037 while (it.next()) |entry| {1024 try self.atom(atom_index).?.resolveRelocs(self);
1038 const atom_index = entry.key_ptr.*;
1039 const relocs = entry.value_ptr.*;
1040 const atom_ptr = self.atom(atom_index).?;
1041 const source_shdr = &self.shdrs.items[atom_ptr.output_section_index];
1042
1043 log.debug("relocating '{s}'", .{atom_ptr.name(self)});
1044
1045 for (relocs.items) |*reloc| {
1046 const target_sym = self.symbol(reloc.target);
1047 const target_vaddr = target_sym.value + reloc.addend;
1048
1049 if (target_vaddr == reloc.prev_vaddr) continue;
1050
1051 const section_offset = (atom_ptr.value + reloc.offset) - source_shdr.sh_addr;
1052 const file_offset = source_shdr.sh_offset + section_offset;
1053
1054 log.debug(" ({x}: [() => 0x{x}] ({s}))", .{
1055 reloc.offset,
1056 target_vaddr,
1057 target_sym.name(self),
1058 });
1059
1060 switch (self.ptr_width) {
1061 .p32 => try self.base.file.?.pwriteAll(mem.asBytes(&@as(u32, @intCast(target_vaddr))), file_offset),
1062 .p64 => try self.base.file.?.pwriteAll(mem.asBytes(&target_vaddr), file_offset),
1063 }
1064
1065 reloc.prev_vaddr = target_vaddr;
1066 }
1067 }1025 }
1068 }1026 }
10691027
...@@ -2313,7 +2271,7 @@ pub fn updateFunc(self: *Elf, mod: *Module, func_index: InternPool.Index, air: A...@@ -2313,7 +2271,7 @@ pub fn updateFunc(self: *Elf, mod: *Module, func_index: InternPool.Index, air: A
23132271
2314 const sym_index = try self.getOrCreateMetadataForDecl(decl_index);2272 const sym_index = try self.getOrCreateMetadataForDecl(decl_index);
2315 self.freeUnnamedConsts(decl_index);2273 self.freeUnnamedConsts(decl_index);
2316 Atom.freeRelocations(self, self.symbol(sym_index).atom_index);2274 self.symbol(sym_index).atom(self).?.freeRelocs(self);
23172275
2318 var code_buffer = std.ArrayList(u8).init(self.base.allocator);2276 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
2319 defer code_buffer.deinit();2277 defer code_buffer.deinit();
...@@ -2378,7 +2336,7 @@ pub fn updateDecl(...@@ -2378,7 +2336,7 @@ pub fn updateDecl(
2378 }2336 }
23792337
2380 const sym_index = try self.getOrCreateMetadataForDecl(decl_index);2338 const sym_index = try self.getOrCreateMetadataForDecl(decl_index);
2381 Atom.freeRelocations(self, self.symbol(sym_index).atom_index);2339 self.symbol(sym_index).atom(self).?.freeRelocs(self);
23822340
2383 var code_buffer = std.ArrayList(u8).init(self.base.allocator);2341 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
2384 defer code_buffer.deinit();2342 defer code_buffer.deinit();
src/link/Elf/Atom.zig+56-25
...@@ -14,13 +14,13 @@ size: u64 = 0,...@@ -14,13 +14,13 @@ size: u64 = 0,
14alignment: u8 = 0,14alignment: u8 = 0,
1515
16/// Index of the input section.16/// Index of the input section.
17input_section_index: u16 = 0,17input_section_index: Index = 0,
1818
19/// Index of the output section.19/// Index of the output section.
20output_section_index: u16 = 0,20output_section_index: u16 = 0,
2121
22/// Index of the input section containing this atom's relocs.22/// Index of the input section containing this atom's relocs.
23relocs_section_index: u16 = 0,23relocs_section_index: Index = 0,
2424
25/// Index of this atom in the linker's atoms table.25/// Index of this atom in the linker's atoms table.
26atom_index: Index = 0,26atom_index: Index = 0,
...@@ -64,20 +64,6 @@ pub fn freeListEligible(self: Atom, elf_file: *Elf) bool {...@@ -64,20 +64,6 @@ pub fn freeListEligible(self: Atom, elf_file: *Elf) bool {
64 return surplus >= Elf.min_text_capacity;64 return surplus >= Elf.min_text_capacity;
65}65}
6666
67pub fn addRelocation(elf_file: *Elf, atom_index: Index, reloc: Reloc) !void {
68 const gpa = elf_file.base.allocator;
69 const gop = try elf_file.relocs.getOrPut(gpa, atom_index);
70 if (!gop.found_existing) {
71 gop.value_ptr.* = .{};
72 }
73 try gop.value_ptr.append(gpa, reloc);
74}
75
76pub fn freeRelocations(elf_file: *Elf, atom_index: Index) void {
77 var removed_relocs = elf_file.relocs.fetchRemove(atom_index);
78 if (removed_relocs) |*relocs| relocs.value.deinit(elf_file.base.allocator);
79}
80
81pub fn allocate(self: *Atom, elf_file: *Elf) !void {67pub fn allocate(self: *Atom, elf_file: *Elf) !void {
82 const shdr = &elf_file.shdrs.items[self.output_section_index];68 const shdr = &elf_file.shdrs.items[self.output_section_index];
83 const meta = elf_file.last_atom_and_free_list_table.getPtr(self.output_section_index).?;69 const meta = elf_file.last_atom_and_free_list_table.getPtr(self.output_section_index).?;
...@@ -205,8 +191,6 @@ pub fn grow(self: *Atom, elf_file: *Elf) !void {...@@ -205,8 +191,6 @@ pub fn grow(self: *Atom, elf_file: *Elf) !void {
205pub fn free(self: *Atom, elf_file: *Elf) void {191pub fn free(self: *Atom, elf_file: *Elf) void {
206 log.debug("freeAtom {d} ({s})", .{ self.atom_index, self.name(elf_file) });192 log.debug("freeAtom {d} ({s})", .{ self.atom_index, self.name(elf_file) });
207193
208 Atom.freeRelocations(elf_file, self.atom_index);
209
210 const gpa = elf_file.base.allocator;194 const gpa = elf_file.base.allocator;
211 const shndx = self.output_section_index;195 const shndx = self.output_section_index;
212 const meta = elf_file.last_atom_and_free_list_table.getPtr(shndx).?;196 const meta = elf_file.last_atom_and_free_list_table.getPtr(shndx).?;
...@@ -256,23 +240,70 @@ pub fn free(self: *Atom, elf_file: *Elf) void {...@@ -256,23 +240,70 @@ pub fn free(self: *Atom, elf_file: *Elf) void {
256 self.next_index = 0;240 self.next_index = 0;
257 }241 }
258242
243 // TODO create relocs free list
244 self.freeRelocs(elf_file);
259 self.* = .{};245 self.* = .{};
260}246}
261247
262pub const Index = u32;248pub fn relocs(self: Atom, elf_file: *Elf) []const Relocation {
249 const file_ptr = elf_file.file(self.file_index).?;
250 if (file_ptr != .zig_module) @panic("TODO");
251 const zig_module = file_ptr.zig_module;
252 return zig_module.relocs.items[self.relocs_section_index].items;
253}
254
255pub fn addReloc(self: Atom, elf_file: *Elf, reloc: Relocation) !void {
256 const gpa = elf_file.base.allocator;
257 const file_ptr = elf_file.file(self.file_index).?;
258 assert(file_ptr == .zig_module);
259 const zig_module = file_ptr.zig_module;
260 const rels = &zig_module.relocs.items[self.relocs_section_index];
261 try rels.append(gpa, reloc);
262}
263
264pub fn freeRelocs(self: Atom, elf_file: *Elf) void {
265 const file_ptr = elf_file.file(self.file_index).?;
266 assert(file_ptr == .zig_module);
267 const zig_module = file_ptr.zig_module;
268 zig_module.relocs.items[self.relocs_section_index].clearRetainingCapacity();
269}
270
271/// TODO mark relocs dirty
272pub fn resolveRelocs(self: Atom, elf_file: *Elf) !void {
273 relocs_log.debug("0x{x}: {s}", .{ self.value, self.name(elf_file) });
274 const shdr = &elf_file.shdrs.items[self.output_section_index];
275 for (self.relocs(elf_file)) |reloc| {
276 const target_sym = elf_file.symbol(reloc.target);
277 const target_vaddr = target_sym.value + reloc.addend;
278 const section_offset = (self.value + reloc.offset) - shdr.sh_addr;
279 const file_offset = shdr.sh_offset + section_offset;
280
281 relocs_log.debug(" ({x}: [() => 0x{x}] ({s}))", .{
282 reloc.offset,
283 target_vaddr,
284 target_sym.name(elf_file),
285 });
286
287 switch (elf_file.ptr_width) {
288 .p32 => try elf_file.base.file.?.pwriteAll(
289 std.mem.asBytes(&@as(u32, @intCast(target_vaddr))),
290 file_offset,
291 ),
292 .p64 => try elf_file.base.file.?.pwriteAll(std.mem.asBytes(&target_vaddr), file_offset),
293 }
294 }
295}
263296
264pub const Reloc = struct {297pub const Index = u32;
265 target: u32,
266 offset: u64,
267 addend: u32,
268 prev_vaddr: u64,
269};
270298
271const std = @import("std");299const std = @import("std");
272const assert = std.debug.assert;300const assert = std.debug.assert;
273const elf = std.elf;301const elf = std.elf;
274const log = std.log.scoped(.link);302const log = std.log.scoped(.link);
303const relocs_log = std.log.scoped(.link_relocs);
275304
305const Allocator = std.mem.Allocator;
276const Atom = @This();306const Atom = @This();
277const Elf = @import("../Elf.zig");307const Elf = @import("../Elf.zig");
278const File = @import("file.zig").File;308const File = @import("file.zig").File;
309const Relocation = @import("Relocation.zig");
src/link/Elf/Relocation.zig created+8
...@@ -0,0 +1,8 @@
1target: Symbol.Index,
2offset: u64,
3addend: u32,
4
5const std = @import("std");
6
7const Symbol = @import("Symbol.zig");
8const Relocation = @This();
src/link/Elf/ZigModule.zig+11-1
...@@ -9,6 +9,7 @@ elf_global_symbols: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},...@@ -9,6 +9,7 @@ elf_global_symbols: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
9global_symbols: std.AutoArrayHashMapUnmanaged(Symbol.Index, void) = .{},9global_symbols: std.AutoArrayHashMapUnmanaged(Symbol.Index, void) = .{},
1010
11atoms: std.ArrayListUnmanaged(Atom.Index) = .{},11atoms: std.ArrayListUnmanaged(Atom.Index) = .{},
12relocs: std.ArrayListUnmanaged(std.ArrayListUnmanaged(Relocation)) = .{},
1213
13alive: bool = true,14alive: bool = true,
1415
...@@ -20,6 +21,10 @@ pub fn deinit(self: *ZigModule, allocator: Allocator) void {...@@ -20,6 +21,10 @@ pub fn deinit(self: *ZigModule, allocator: Allocator) void {
20 self.elf_global_symbols.deinit(allocator);21 self.elf_global_symbols.deinit(allocator);
21 self.global_symbols.deinit(allocator);22 self.global_symbols.deinit(allocator);
22 self.atoms.deinit(allocator);23 self.atoms.deinit(allocator);
24 for (self.relocs.items) |*list| {
25 list.deinit(allocator);
26 }
27 self.relocs.deinit(allocator);
23}28}
2429
25pub fn createAtom(self: *ZigModule, output_section_index: u16, elf_file: *Elf) !Symbol.Index {30pub fn createAtom(self: *ZigModule, output_section_index: u16, elf_file: *Elf) !Symbol.Index {
...@@ -34,6 +39,10 @@ pub fn createAtom(self: *ZigModule, output_section_index: u16, elf_file: *Elf) !...@@ -34,6 +39,10 @@ pub fn createAtom(self: *ZigModule, output_section_index: u16, elf_file: *Elf) !
34 symbol_ptr.output_section_index = output_section_index;39 symbol_ptr.output_section_index = output_section_index;
35 const local_esym = symbol_ptr.sourceSymbol(elf_file);40 const local_esym = symbol_ptr.sourceSymbol(elf_file);
36 local_esym.st_shndx = output_section_index;41 local_esym.st_shndx = output_section_index;
42 const relocs_index = @as(Atom.Index, @intCast(self.relocs.items.len));
43 const relocs = try self.relocs.addOne(gpa);
44 relocs.* = .{};
45 atom_ptr.relocs_section_index = relocs_index;
37 try self.atoms.append(gpa, atom_index);46 try self.atoms.append(gpa, atom_index);
38 return symbol_index;47 return symbol_index;
39}48}
...@@ -184,5 +193,6 @@ const Atom = @import("Atom.zig");...@@ -184,5 +193,6 @@ const Atom = @import("Atom.zig");
184const Elf = @import("../Elf.zig");193const Elf = @import("../Elf.zig");
185const File = @import("file.zig").File;194const File = @import("file.zig").File;
186const Module = @import("../../Module.zig");195const Module = @import("../../Module.zig");
187const ZigModule = @This();196const Relocation = @import("Relocation.zig");
188const Symbol = @import("Symbol.zig");197const Symbol = @import("Symbol.zig");
198const ZigModule = @This();