| ... | @@ -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 | }; |
| 65 | | 65 | |
| | 66 | const 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 | |
| 66 | const LazySymbolMetadata = struct { | 148 | const 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) = .{}, |
| 148 | | 230 | |
| 149 | local_symbol_free_list: std.ArrayListUnmanaged(u32) = .{}, | 231 | local_symbol_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 150 | global_symbol_free_list: std.ArrayListUnmanaged(u32) = .{}, | 232 | global_symbol_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 151 | offset_table_free_list: std.ArrayListUnmanaged(u32) = .{}, | | |
| 152 | | 233 | |
| 153 | /// Same order as in the file. The value is the absolute vaddr value. | 234 | got_table: SectionTable = .{}, |
| 154 | /// If the vaddr of the executable program header changes, the entire | | |
| 155 | /// offset table needs to be rewritten. | | |
| 156 | offset_table: std.ArrayListUnmanaged(u64) = .{}, | | |
| 157 | | 235 | |
| 158 | phdr_table_dirty: bool = false, | 236 | phdr_table_dirty: bool = false, |
| 159 | shdr_table_dirty: bool = false, | 237 | shdr_table_dirty: bool = false, |
| 160 | shstrtab_dirty: bool = false, | 238 | shstrtab_dirty: bool = false, |
| 161 | offset_table_count_dirty: bool = false, | 239 | got_table_count_dirty: bool = false, |
| 162 | | 240 | |
| 163 | debug_strtab_dirty: bool = false, | 241 | debug_strtab_dirty: bool = false, |
| 164 | debug_abbrev_section_dirty: bool = false, | 242 | debug_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); | | |
| 334 | | 411 | |
| 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 | } |
| 1293 | | 1371 | |
| 1294 | fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !void { | 1372 | fn 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; |
| 2170 | | 2248 | |
| 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 | } |
| 2173 | | 2251 | |
| 2174 | fn shrinkAtom(self: *Elf, atom_index: Atom.Index, new_block_size: u64) void { | 2252 | fn 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 | } |
| 2354 | | 2430 | |
| 2355 | pub 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 | | | |
| 2375 | fn freeUnnamedConsts(self: *Elf, decl_index: Module.Decl.Index) void { | 2431 | fn 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().?; |
| 2468 | | 2525 | |
| 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; |
| 2486 | | 2543 | |
| 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; |
| 2495 | | 2553 | |
| 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 }); |
| 2511 | | 2569 | |
| 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; |
| 2515 | | 2572 | |
| 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 | } |
| 2519 | | 2577 | |
| 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 }); |
| 2757 | | 2815 | |
| 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; |
| 2761 | | 2818 | |
| 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); |
| 2764 | | 2822 | |
| 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 { |
| 2991 | | 3049 | |
| 2992 | fn writeOffsetTableEntry(self: *Elf, index: usize) !void { | 3050 | fn 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); |
| 3019 | | 3079 | |
| 3020 | if (self.base.child_pid) |pid| { | 3080 | if (self.base.child_pid) |pid| { |