| 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,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`. |
| 136 | unnamed_consts: UnnamedConstTable = .{}, | 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 | const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Symbol.Index)); | 138 | const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Symbol.Index)); |
| 143 | const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata); | 139 | const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata); |
| 144 | 140 | ||
| ... | @@ -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 | } |
| 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 | 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 | }); |
| 322 | 309 | ||
| 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 |
| 1032 | 1019 | ||
| 1033 | // Beyond this point, everything has been allocated a virtual address and we can resolve | 1020 | // 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 | } |
| 1069 | 1027 | ||
| ... | @@ -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 |
| 2313 | 2271 | ||
| 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); |
| 2317 | 2275 | ||
| 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 | } |
| 2379 | 2337 | ||
| 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); |
| 2382 | 2340 | ||
| 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, |
| 14 | alignment: u8 = 0, | 14 | alignment: u8 = 0, |
| 15 | 15 | ||
| 16 | /// Index of the input section. | 16 | /// Index of the input section. |
| 17 | input_section_index: u16 = 0, | 17 | input_section_index: Index = 0, |
| 18 | 18 | ||
| 19 | /// Index of the output section. | 19 | /// Index of the output section. |
| 20 | output_section_index: u16 = 0, | 20 | output_section_index: u16 = 0, |
| 21 | 21 | ||
| 22 | /// Index of the input section containing this atom's relocs. | 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 | /// Index of this atom in the linker's atoms table. | 25 | /// Index of this atom in the linker's atoms table. |
| 26 | atom_index: Index = 0, | 26 | atom_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 | } |
| 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 | pub fn allocate(self: *Atom, elf_file: *Elf) !void { | 67 | pub 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 { |
| 205 | pub fn free(self: *Atom, elf_file: *Elf) void { | 191 | pub 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) }); |
| 207 | 193 | ||
| 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 | } |
| 258 | 242 | ||
| 243 | // TODO create relocs free list | ||
| 244 | self.freeRelocs(elf_file); | ||
| 259 | self.* = .{}; | 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 { | 297 | pub const Index = u32; |
| 265 | target: u32, | ||
| 266 | offset: u64, | ||
| 267 | addend: u32, | ||
| 268 | prev_vaddr: u64, | ||
| 269 | }; | ||
| 270 | 298 | ||
| 271 | const std = @import("std"); | 299 | const std = @import("std"); |
| 272 | const assert = std.debug.assert; | 300 | const assert = std.debug.assert; |
| 273 | const elf = std.elf; | 301 | const elf = std.elf; |
| 274 | const log = std.log.scoped(.link); | 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 | const Atom = @This(); | 306 | const Atom = @This(); |
| 277 | const Elf = @import("../Elf.zig"); | 307 | const Elf = @import("../Elf.zig"); |
| 278 | const File = @import("file.zig").File; | 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,6 +9,7 @@ elf_global_symbols: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{}, |
| 9 | global_symbols: std.AutoArrayHashMapUnmanaged(Symbol.Index, void) = .{}, | 9 | global_symbols: std.AutoArrayHashMapUnmanaged(Symbol.Index, void) = .{}, |
| 10 | 10 | ||
| 11 | atoms: std.ArrayListUnmanaged(Atom.Index) = .{}, | 11 | atoms: std.ArrayListUnmanaged(Atom.Index) = .{}, |
| 12 | relocs: std.ArrayListUnmanaged(std.ArrayListUnmanaged(Relocation)) = .{}, | ||
| 12 | 13 | ||
| 13 | alive: bool = true, | 14 | alive: bool = true, |
| 14 | 15 | ||
| ... | @@ -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 | } |
| 24 | 29 | ||
| 25 | pub fn createAtom(self: *ZigModule, output_section_index: u16, elf_file: *Elf) !Symbol.Index { | 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,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"); |
| 184 | const Elf = @import("../Elf.zig"); | 193 | const Elf = @import("../Elf.zig"); |
| 185 | const File = @import("file.zig").File; | 194 | const File = @import("file.zig").File; |
| 186 | const Module = @import("../../Module.zig"); | 195 | const Module = @import("../../Module.zig"); |
| 187 | const ZigModule = @This(); | 196 | const Relocation = @import("Relocation.zig"); |
| 188 | const Symbol = @import("Symbol.zig"); | 197 | const Symbol = @import("Symbol.zig"); |
| 198 | const ZigModule = @This(); |