| author | |
| committer | |
| log | d07edfabd6e45a486d1611e357887d01b38db32e |
| tree | f65dfcc372dddb4ccaf649ca4d22f582f7f5bcf2 |
| parent | 4b082d89c9cd6e40259701f21344d55eef2a8d2e |
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 | 135 | /// with `Decl` `main`, and lives as long as that `Decl`. |
| 136 | 136 | unnamed_consts: UnnamedConstTable = .{}, |
| 137 | 137 | |
| 138 | /// A table of relocations indexed by the owning them `TextBlock`. | |
| 139 | relocs: RelocTable = .{}, | |
| 140 | ||
| 141 | const RelocTable = std.AutoHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Atom.Reloc)); | |
| 142 | 138 | const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Symbol.Index)); |
| 143 | 139 | const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata); |
| 144 | 140 | |
| ... | ... | @@ -293,14 +289,6 @@ pub fn deinit(self: *Elf) void { |
| 293 | 289 | self.unnamed_consts.deinit(gpa); |
| 294 | 290 | } |
| 295 | 291 | |
| 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 | 292 | if (self.dwarf) |*dw| { |
| 305 | 293 | dw.deinit(); |
| 306 | 294 | } |
| ... | ... | @@ -312,12 +300,11 @@ pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: link. |
| 312 | 300 | const this_sym_index = try self.getOrCreateMetadataForDecl(decl_index); |
| 313 | 301 | const this_sym = self.symbol(this_sym_index); |
| 314 | 302 | const vaddr = this_sym.value; |
| 315 | const parent_atom_index = self.symbol(reloc_info.parent_atom_index).atom_index; | |
| 316 | try Atom.addRelocation(self, parent_atom_index, .{ | |
| 303 | const parent_atom = self.symbol(reloc_info.parent_atom_index).atom(self).?; | |
| 304 | try parent_atom.addReloc(self, .{ | |
| 317 | 305 | .target = this_sym_index, |
| 318 | 306 | .offset = reloc_info.offset, |
| 319 | 307 | .addend = reloc_info.addend, |
| 320 | .prev_vaddr = vaddr, | |
| 321 | 308 | }); |
| 322 | 309 | |
| 323 | 310 | return vaddr; |
| ... | ... | @@ -1032,38 +1019,9 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node |
| 1032 | 1019 | |
| 1033 | 1020 | // Beyond this point, everything has been allocated a virtual address and we can resolve |
| 1034 | 1021 | // the relocations. |
| 1035 | { | |
| 1036 | var it = self.relocs.iterator(); | |
| 1037 | while (it.next()) |entry| { | |
| 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 | } | |
| 1022 | if (self.zig_module_index) |index| { | |
| 1023 | for (self.file(index).?.zig_module.atoms.items) |atom_index| { | |
| 1024 | try self.atom(atom_index).?.resolveRelocs(self); | |
| 1067 | 1025 | } |
| 1068 | 1026 | } |
| 1069 | 1027 | |
| ... | ... | @@ -2313,7 +2271,7 @@ pub fn updateFunc(self: *Elf, mod: *Module, func_index: InternPool.Index, air: A |
| 2313 | 2271 | |
| 2314 | 2272 | const sym_index = try self.getOrCreateMetadataForDecl(decl_index); |
| 2315 | 2273 | self.freeUnnamedConsts(decl_index); |
| 2316 | Atom.freeRelocations(self, self.symbol(sym_index).atom_index); | |
| 2274 | self.symbol(sym_index).atom(self).?.freeRelocs(self); | |
| 2317 | 2275 | |
| 2318 | 2276 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 2319 | 2277 | defer code_buffer.deinit(); |
| ... | ... | @@ -2378,7 +2336,7 @@ pub fn updateDecl( |
| 2378 | 2336 | } |
| 2379 | 2337 | |
| 2380 | 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); | |
| 2382 | 2340 | |
| 2383 | 2341 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 2384 | 2342 | defer code_buffer.deinit(); |
src/link/Elf/Atom.zig+56-25| ... | ... | @@ -14,13 +14,13 @@ size: u64 = 0, |
| 14 | 14 | alignment: u8 = 0, |
| 15 | 15 | |
| 16 | 16 | /// Index of the input section. |
| 17 | input_section_index: u16 = 0, | |
| 17 | input_section_index: Index = 0, | |
| 18 | 18 | |
| 19 | 19 | /// Index of the output section. |
| 20 | 20 | output_section_index: u16 = 0, |
| 21 | 21 | |
| 22 | 22 | /// Index of the input section containing this atom's relocs. |
| 23 | relocs_section_index: u16 = 0, | |
| 23 | relocs_section_index: Index = 0, | |
| 24 | 24 | |
| 25 | 25 | /// Index of this atom in the linker's atoms table. |
| 26 | 26 | atom_index: Index = 0, |
| ... | ... | @@ -64,20 +64,6 @@ pub fn freeListEligible(self: Atom, elf_file: *Elf) bool { |
| 64 | 64 | return surplus >= Elf.min_text_capacity; |
| 65 | 65 | } |
| 66 | 66 | |
| 67 | pub 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 | ||
| 76 | pub 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 | ||
| 81 | 67 | pub fn allocate(self: *Atom, elf_file: *Elf) !void { |
| 82 | 68 | const shdr = &elf_file.shdrs.items[self.output_section_index]; |
| 83 | 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 | 191 | pub fn free(self: *Atom, elf_file: *Elf) void { |
| 206 | 192 | log.debug("freeAtom {d} ({s})", .{ self.atom_index, self.name(elf_file) }); |
| 207 | 193 | |
| 208 | Atom.freeRelocations(elf_file, self.atom_index); | |
| 209 | ||
| 210 | 194 | const gpa = elf_file.base.allocator; |
| 211 | 195 | const shndx = self.output_section_index; |
| 212 | 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 | 240 | self.next_index = 0; |
| 257 | 241 | } |
| 258 | 242 | |
| 243 | // TODO create relocs free list | |
| 244 | self.freeRelocs(elf_file); | |
| 259 | 245 | self.* = .{}; |
| 260 | 246 | } |
| 261 | 247 | |
| 262 | pub const Index = u32; | |
| 248 | pub 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 | ||
| 255 | pub 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 | ||
| 264 | pub 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 | |
| 272 | pub 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 | } | |
| 263 | 296 | |
| 264 | pub const Reloc = struct { | |
| 265 | target: u32, | |
| 266 | offset: u64, | |
| 267 | addend: u32, | |
| 268 | prev_vaddr: u64, | |
| 269 | }; | |
| 297 | pub const Index = u32; | |
| 270 | 298 | |
| 271 | 299 | const std = @import("std"); |
| 272 | 300 | const assert = std.debug.assert; |
| 273 | 301 | const elf = std.elf; |
| 274 | 302 | const log = std.log.scoped(.link); |
| 303 | const relocs_log = std.log.scoped(.link_relocs); | |
| 275 | 304 | |
| 305 | const Allocator = std.mem.Allocator; | |
| 276 | 306 | const Atom = @This(); |
| 277 | 307 | const Elf = @import("../Elf.zig"); |
| 278 | 308 | const File = @import("file.zig").File; |
| 309 | const Relocation = @import("Relocation.zig"); |
src/link/Elf/Relocation.zig created+8| ... | ... | @@ -0,0 +1,8 @@ |
| 1 | target: Symbol.Index, | |
| 2 | offset: u64, | |
| 3 | addend: u32, | |
| 4 | ||
| 5 | const std = @import("std"); | |
| 6 | ||
| 7 | const Symbol = @import("Symbol.zig"); | |
| 8 | const Relocation = @This(); |
src/link/Elf/ZigModule.zig+11-1| ... | ... | @@ -9,6 +9,7 @@ elf_global_symbols: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{}, |
| 9 | 9 | global_symbols: std.AutoArrayHashMapUnmanaged(Symbol.Index, void) = .{}, |
| 10 | 10 | |
| 11 | 11 | atoms: std.ArrayListUnmanaged(Atom.Index) = .{}, |
| 12 | relocs: std.ArrayListUnmanaged(std.ArrayListUnmanaged(Relocation)) = .{}, | |
| 12 | 13 | |
| 13 | 14 | alive: bool = true, |
| 14 | 15 | |
| ... | ... | @@ -20,6 +21,10 @@ pub fn deinit(self: *ZigModule, allocator: Allocator) void { |
| 20 | 21 | self.elf_global_symbols.deinit(allocator); |
| 21 | 22 | self.global_symbols.deinit(allocator); |
| 22 | 23 | self.atoms.deinit(allocator); |
| 24 | for (self.relocs.items) |*list| { | |
| 25 | list.deinit(allocator); | |
| 26 | } | |
| 27 | self.relocs.deinit(allocator); | |
| 23 | 28 | } |
| 24 | 29 | |
| 25 | 30 | pub 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 | 39 | symbol_ptr.output_section_index = output_section_index; |
| 35 | 40 | const local_esym = symbol_ptr.sourceSymbol(elf_file); |
| 36 | 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 | 46 | try self.atoms.append(gpa, atom_index); |
| 38 | 47 | return symbol_index; |
| 39 | 48 | } |
| ... | ... | @@ -184,5 +193,6 @@ const Atom = @import("Atom.zig"); |
| 184 | 193 | const Elf = @import("../Elf.zig"); |
| 185 | 194 | const File = @import("file.zig").File; |
| 186 | 195 | const Module = @import("../../Module.zig"); |
| 187 | const ZigModule = @This(); | |
| 196 | const Relocation = @import("Relocation.zig"); | |
| 188 | 197 | const Symbol = @import("Symbol.zig"); |
| 198 | const ZigModule = @This(); |