authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-10 14:41:07+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-11 10:52:13+01:00
logb9b1ab024063105a9adfe3828692867c91015dc6
treeae0c2e67953f9fbb308ecb17d5bdd8438747cca9
parent08e2f5d08390d41b58c92707693385e5e2968fc8

elf: store pointer relocations indexed by containing atom

In `getDeclVAddr`, it may happen that the target `Decl` has not been allocated space in virtual memory. In this case, we store a relocation in the linker-global table which we will iterate over when flushing the module, and fill in any missing address in the final binary. Note that for optimisation, if the address was resolved at the time of a call to `getDeclVAddr`, we skip relocating this atom. This commit also adds the glue code for lowering const slices in the ARM backend.

7 files changed, 163 insertions(+), 86 deletions(-)

src/arch/arm/CodeGen.zig+11-14
...@@ -3931,23 +3931,20 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {...@@ -3931,23 +3931,20 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
3931 switch (typed_value.ty.zigTypeTag()) {3931 switch (typed_value.ty.zigTypeTag()) {
3932 .Pointer => switch (typed_value.ty.ptrSize()) {3932 .Pointer => switch (typed_value.ty.ptrSize()) {
3933 .Slice => {3933 .Slice => {
3934 var buf: Type.SlicePtrFieldTypeBuffer = undefined;3934 return self.lowerUnnamedConst(typed_value);
3935 const ptr_type = typed_value.ty.slicePtrFieldType(&buf);
3936 const ptr_mcv = try self.genTypedValue(.{ .ty = ptr_type, .val = typed_value.val });
3937 const slice_len = typed_value.val.sliceLen();
3938 // Codegen can't handle some kinds of indirection. If the wrong union field is accessed here it may mean
3939 // the Sema code needs to use anonymous Decls or alloca instructions to store data.
3940 const ptr_imm = ptr_mcv.memory;
3941 _ = slice_len;
3942 _ = ptr_imm;
3943 // We need more general support for const data being stored in memory to make this work.
3944 return self.fail("TODO codegen for const slices", .{});
3945 },3935 },
3946 else => {3936 else => {
3947 if (typed_value.val.tag() == .int_u64) {3937 switch (typed_value.val.tag()) {
3948 return MCValue{ .immediate = @intCast(u32, typed_value.val.toUnsignedInt()) };3938 .int_u64 => {
3939 return MCValue{ .immediate = @intCast(u32, typed_value.val.toUnsignedInt()) };
3940 },
3941 .slice => {
3942 return self.lowerUnnamedConst(typed_value);
3943 },
3944 else => {
3945 return self.fail("TODO codegen more kinds of const pointers", .{});
3946 },
3949 }3947 }
3950 return self.fail("TODO codegen more kinds of const pointers", .{});
3951 },3948 },
3952 },3949 },
3953 .Int => {3950 .Int => {
src/codegen.zig+12-18
...@@ -142,6 +142,7 @@ pub fn generateFunction(...@@ -142,6 +142,7 @@ pub fn generateFunction(
142142
143pub fn generateSymbol(143pub fn generateSymbol(
144 bin_file: *link.File,144 bin_file: *link.File,
145 parent_atom_index: u32,
145 src_loc: Module.SrcLoc,146 src_loc: Module.SrcLoc,
146 typed_value: TypedValue,147 typed_value: TypedValue,
147 code: *std.ArrayList(u8),148 code: *std.ArrayList(u8),
...@@ -177,7 +178,7 @@ pub fn generateSymbol(...@@ -177,7 +178,7 @@ pub fn generateSymbol(
177 if (typed_value.ty.sentinel()) |sentinel| {178 if (typed_value.ty.sentinel()) |sentinel| {
178 try code.ensureUnusedCapacity(payload.data.len + 1);179 try code.ensureUnusedCapacity(payload.data.len + 1);
179 code.appendSliceAssumeCapacity(payload.data);180 code.appendSliceAssumeCapacity(payload.data);
180 switch (try generateSymbol(bin_file, src_loc, .{181 switch (try generateSymbol(bin_file, parent_atom_index, src_loc, .{
181 .ty = typed_value.ty.elemType(),182 .ty = typed_value.ty.elemType(),
182 .val = sentinel,183 .val = sentinel,
183 }, code, debug_output)) {184 }, code, debug_output)) {
...@@ -197,7 +198,7 @@ pub fn generateSymbol(...@@ -197,7 +198,7 @@ pub fn generateSymbol(
197 const elem_vals = typed_value.val.castTag(.array).?.data;198 const elem_vals = typed_value.val.castTag(.array).?.data;
198 const elem_ty = typed_value.ty.elemType();199 const elem_ty = typed_value.ty.elemType();
199 for (elem_vals) |elem_val| {200 for (elem_vals) |elem_val| {
200 switch (try generateSymbol(bin_file, src_loc, .{201 switch (try generateSymbol(bin_file, parent_atom_index, src_loc, .{
201 .ty = elem_ty,202 .ty = elem_ty,
202 .val = elem_val,203 .val = elem_val,
203 }, code, debug_output)) {204 }, code, debug_output)) {
...@@ -223,11 +224,11 @@ pub fn generateSymbol(...@@ -223,11 +224,11 @@ pub fn generateSymbol(
223 .Pointer => switch (typed_value.val.tag()) {224 .Pointer => switch (typed_value.val.tag()) {
224 .variable => {225 .variable => {
225 const decl = typed_value.val.castTag(.variable).?.data.owner_decl;226 const decl = typed_value.val.castTag(.variable).?.data.owner_decl;
226 return lowerDeclRef(bin_file, src_loc, typed_value, decl, code, debug_output);227 return lowerDeclRef(bin_file, parent_atom_index, src_loc, typed_value, decl, code, debug_output);
227 },228 },
228 .decl_ref => {229 .decl_ref => {
229 const decl = typed_value.val.castTag(.decl_ref).?.data;230 const decl = typed_value.val.castTag(.decl_ref).?.data;
230 return lowerDeclRef(bin_file, src_loc, typed_value, decl, code, debug_output);231 return lowerDeclRef(bin_file, parent_atom_index, src_loc, typed_value, decl, code, debug_output);
231 },232 },
232 .slice => {233 .slice => {
233 const slice = typed_value.val.castTag(.slice).?.data;234 const slice = typed_value.val.castTag(.slice).?.data;
...@@ -235,7 +236,7 @@ pub fn generateSymbol(...@@ -235,7 +236,7 @@ pub fn generateSymbol(
235 // generate ptr236 // generate ptr
236 var buf: Type.SlicePtrFieldTypeBuffer = undefined;237 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
237 const slice_ptr_field_type = typed_value.ty.slicePtrFieldType(&buf);238 const slice_ptr_field_type = typed_value.ty.slicePtrFieldType(&buf);
238 switch (try generateSymbol(bin_file, src_loc, .{239 switch (try generateSymbol(bin_file, parent_atom_index, src_loc, .{
239 .ty = slice_ptr_field_type,240 .ty = slice_ptr_field_type,
240 .val = slice.ptr,241 .val = slice.ptr,
241 }, code, debug_output)) {242 }, code, debug_output)) {
...@@ -247,7 +248,7 @@ pub fn generateSymbol(...@@ -247,7 +248,7 @@ pub fn generateSymbol(
247 }248 }
248249
249 // generate length250 // generate length
250 switch (try generateSymbol(bin_file, src_loc, .{251 switch (try generateSymbol(bin_file, parent_atom_index, src_loc, .{
251 .ty = Type.initTag(.usize),252 .ty = Type.initTag(.usize),
252 .val = slice.len,253 .val = slice.len,
253 }, code, debug_output)) {254 }, code, debug_output)) {
...@@ -391,7 +392,7 @@ pub fn generateSymbol(...@@ -391,7 +392,7 @@ pub fn generateSymbol(
391 const field_ty = typed_value.ty.structFieldType(index);392 const field_ty = typed_value.ty.structFieldType(index);
392 if (!field_ty.hasRuntimeBits()) continue;393 if (!field_ty.hasRuntimeBits()) continue;
393394
394 switch (try generateSymbol(bin_file, src_loc, .{395 switch (try generateSymbol(bin_file, parent_atom_index, src_loc, .{
395 .ty = field_ty,396 .ty = field_ty,
396 .val = field_val,397 .val = field_val,
397 }, code, debug_output)) {398 }, code, debug_output)) {
...@@ -446,6 +447,7 @@ pub fn generateSymbol(...@@ -446,6 +447,7 @@ pub fn generateSymbol(
446447
447fn lowerDeclRef(448fn lowerDeclRef(
448 bin_file: *link.File,449 bin_file: *link.File,
450 parent_atom_index: u32,
449 src_loc: Module.SrcLoc,451 src_loc: Module.SrcLoc,
450 typed_value: TypedValue,452 typed_value: TypedValue,
451 decl: *Module.Decl,453 decl: *Module.Decl,
...@@ -456,7 +458,7 @@ fn lowerDeclRef(...@@ -456,7 +458,7 @@ fn lowerDeclRef(
456 // generate ptr458 // generate ptr
457 var buf: Type.SlicePtrFieldTypeBuffer = undefined;459 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
458 const slice_ptr_field_type = typed_value.ty.slicePtrFieldType(&buf);460 const slice_ptr_field_type = typed_value.ty.slicePtrFieldType(&buf);
459 switch (try generateSymbol(bin_file, src_loc, .{461 switch (try generateSymbol(bin_file, parent_atom_index, src_loc, .{
460 .ty = slice_ptr_field_type,462 .ty = slice_ptr_field_type,
461 .val = typed_value.val,463 .val = typed_value.val,
462 }, code, debug_output)) {464 }, code, debug_output)) {
...@@ -472,7 +474,7 @@ fn lowerDeclRef(...@@ -472,7 +474,7 @@ fn lowerDeclRef(
472 .base = .{ .tag = .int_u64 },474 .base = .{ .tag = .int_u64 },
473 .data = typed_value.val.sliceLen(),475 .data = typed_value.val.sliceLen(),
474 };476 };
475 switch (try generateSymbol(bin_file, src_loc, .{477 switch (try generateSymbol(bin_file, parent_atom_index, src_loc, .{
476 .ty = Type.initTag(.usize),478 .ty = Type.initTag(.usize),
477 .val = Value.initPayload(&slice_len.base),479 .val = Value.initPayload(&slice_len.base),
478 }, code, debug_output)) {480 }, code, debug_output)) {
...@@ -495,15 +497,7 @@ fn lowerDeclRef(...@@ -495,15 +497,7 @@ fn lowerDeclRef(
495 }497 }
496498
497 decl.markAlive();499 decl.markAlive();
498 const vaddr = vaddr: {500 const vaddr = try bin_file.getDeclVAddr(decl, parent_atom_index, code.items.len);
499 if (bin_file.cast(link.File.MachO)) |macho_file| {
500 break :vaddr try macho_file.getDeclVAddrWithReloc(decl, code.items.len);
501 }
502 // TODO handle the dependency of this symbol on the decl's vaddr.
503 // If the decl changes vaddr, then this symbol needs to get regenerated.
504 break :vaddr bin_file.getDeclVAddr(decl);
505 };
506
507 const endian = target.cpu.arch.endian();501 const endian = target.cpu.arch.endian();
508 switch (ptr_width) {502 switch (ptr_width) {
509 16 => mem.writeInt(u16, try code.addManyAsArray(2), @intCast(u16, vaddr), endian),503 16 => mem.writeInt(u16, try code.addManyAsArray(2), @intCast(u16, vaddr), endian),
src/link.zig+9-5
...@@ -684,12 +684,16 @@ pub const File = struct {...@@ -684,12 +684,16 @@ pub const File = struct {
684 }684 }
685 }685 }
686686
687 pub fn getDeclVAddr(base: *File, decl: *const Module.Decl) u64 {687 /// Get allocated `Decl`'s address in virtual memory.
688 /// The linker is passed information about the containing atom, `parent_atom_index`, and offset within it's
689 /// memory buffer, `offset`, so that it can make a note of potential relocation sites, should the
690 /// `Decl`'s address was not yet resolved, or the containing atom gets moved in virtual memory.
691 pub fn getDeclVAddr(base: *File, decl: *const Module.Decl, parent_atom_index: u32, offset: u64) !u64 {
688 switch (base.tag) {692 switch (base.tag) {
689 .coff => return @fieldParentPtr(Coff, "base", base).getDeclVAddr(decl),693 .coff => return @fieldParentPtr(Coff, "base", base).getDeclVAddr(decl, parent_atom_index, offset),
690 .elf => return @fieldParentPtr(Elf, "base", base).getDeclVAddr(decl),694 .elf => return @fieldParentPtr(Elf, "base", base).getDeclVAddr(decl, parent_atom_index, offset),
691 .macho => return @fieldParentPtr(MachO, "base", base).getDeclVAddr(decl),695 .macho => return @fieldParentPtr(MachO, "base", base).getDeclVAddr(decl, parent_atom_index, offset),
692 .plan9 => return @fieldParentPtr(Plan9, "base", base).getDeclVAddr(decl),696 .plan9 => return @fieldParentPtr(Plan9, "base", base).getDeclVAddr(decl, parent_atom_index, offset),
693 .c => unreachable,697 .c => unreachable,
694 .wasm => unreachable,698 .wasm => unreachable,
695 .spirv => unreachable,699 .spirv => unreachable,
src/link/Coff.zig+5-3
...@@ -726,7 +726,7 @@ pub fn updateDecl(self: *Coff, module: *Module, decl: *Module.Decl) !void {...@@ -726,7 +726,7 @@ pub fn updateDecl(self: *Coff, module: *Module, decl: *Module.Decl) !void {
726 var code_buffer = std.ArrayList(u8).init(self.base.allocator);726 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
727 defer code_buffer.deinit();727 defer code_buffer.deinit();
728728
729 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{729 const res = try codegen.generateSymbol(&self.base, 0, decl.srcLoc(), .{
730 .ty = decl.ty,730 .ty = decl.ty,
731 .val = decl.val,731 .val = decl.val,
732 }, &code_buffer, .none);732 }, &code_buffer, .none);
...@@ -751,7 +751,7 @@ fn finishUpdateDecl(self: *Coff, module: *Module, decl: *Module.Decl, code: []co...@@ -751,7 +751,7 @@ fn finishUpdateDecl(self: *Coff, module: *Module, decl: *Module.Decl, code: []co
751 const need_realloc = code.len > capacity or751 const need_realloc = code.len > capacity or
752 !mem.isAlignedGeneric(u32, decl.link.coff.text_offset, required_alignment);752 !mem.isAlignedGeneric(u32, decl.link.coff.text_offset, required_alignment);
753 if (need_realloc) {753 if (need_realloc) {
754 const curr_vaddr = self.getDeclVAddr(decl);754 const curr_vaddr = self.text_section_virtual_address + decl.link.coff.text_offset;
755 const vaddr = try self.growTextBlock(&decl.link.coff, code.len, required_alignment);755 const vaddr = try self.growTextBlock(&decl.link.coff, code.len, required_alignment);
756 log.debug("growing {s} from 0x{x} to 0x{x}\n", .{ decl.name, curr_vaddr, vaddr });756 log.debug("growing {s} from 0x{x} to 0x{x}\n", .{ decl.name, curr_vaddr, vaddr });
757 if (vaddr != curr_vaddr) {757 if (vaddr != curr_vaddr) {
...@@ -1465,7 +1465,9 @@ fn findLib(self: *Coff, arena: Allocator, name: []const u8) !?[]const u8 {...@@ -1465,7 +1465,9 @@ fn findLib(self: *Coff, arena: Allocator, name: []const u8) !?[]const u8 {
1465 return null;1465 return null;
1466}1466}
14671467
1468pub fn getDeclVAddr(self: *Coff, decl: *const Module.Decl) u64 {1468pub fn getDeclVAddr(self: *Coff, decl: *const Module.Decl, parent_atom_index: u32, offset: u64) !u64 {
1469 _ = parent_atom_index;
1470 _ = offset;
1469 assert(self.llvm_object == null);1471 assert(self.llvm_object == null);
1470 return self.text_section_virtual_address + decl.link.coff.text_offset;1472 return self.text_section_virtual_address + decl.link.coff.text_offset;
1471}1473}
src/link/Elf.zig+94-19
...@@ -145,6 +145,7 @@ decls: std.AutoHashMapUnmanaged(*Module.Decl, ?u16) = .{},...@@ -145,6 +145,7 @@ decls: std.AutoHashMapUnmanaged(*Module.Decl, ?u16) = .{},
145/// at present owned by Module.Decl.145/// at present owned by Module.Decl.
146/// TODO consolidate this.146/// TODO consolidate this.
147managed_atoms: std.ArrayListUnmanaged(*TextBlock) = .{},147managed_atoms: std.ArrayListUnmanaged(*TextBlock) = .{},
148atom_by_index_table: std.AutoHashMapUnmanaged(u32, *TextBlock) = .{},
148149
149/// Table of unnamed constants associated with a parent `Decl`.150/// Table of unnamed constants associated with a parent `Decl`.
150/// We store them here so that we can free the constants whenever the `Decl`151/// We store them here so that we can free the constants whenever the `Decl`
...@@ -179,6 +180,18 @@ dbg_info_decl_free_list: std.AutoHashMapUnmanaged(*TextBlock, void) = .{},...@@ -179,6 +180,18 @@ dbg_info_decl_free_list: std.AutoHashMapUnmanaged(*TextBlock, void) = .{},
179dbg_info_decl_first: ?*TextBlock = null,180dbg_info_decl_first: ?*TextBlock = null,
180dbg_info_decl_last: ?*TextBlock = null,181dbg_info_decl_last: ?*TextBlock = null,
181182
183/// A table of relocations indexed by the owning them `TextBlock`.
184/// Note that once we refactor `TextBlock`'s lifetime and ownership rules,
185/// this will be a table indexed by index into the list of Atoms.
186relocs: RelocTable = .{},
187
188const Reloc = struct {
189 target: u32,
190 offset: u64,
191 prev_vaddr: u64,
192};
193
194const RelocTable = std.AutoHashMapUnmanaged(*TextBlock, std.ArrayListUnmanaged(Reloc));
182const UnnamedConstTable = std.AutoHashMapUnmanaged(*Module.Decl, std.ArrayListUnmanaged(*TextBlock));195const UnnamedConstTable = std.AutoHashMapUnmanaged(*Module.Decl, std.ArrayListUnmanaged(*TextBlock));
183196
184/// When allocating, the ideal_capacity is calculated by197/// When allocating, the ideal_capacity is calculated by
...@@ -397,12 +410,36 @@ pub fn deinit(self: *Elf) void {...@@ -397,12 +410,36 @@ pub fn deinit(self: *Elf) void {
397 }410 }
398 self.unnamed_const_atoms.deinit(self.base.allocator);411 self.unnamed_const_atoms.deinit(self.base.allocator);
399 }412 }
413
414 {
415 var it = self.relocs.valueIterator();
416 while (it.next()) |relocs| {
417 relocs.deinit(self.base.allocator);
418 }
419 self.relocs.deinit(self.base.allocator);
420 }
421
422 self.atom_by_index_table.deinit(self.base.allocator);
400}423}
401424
402pub fn getDeclVAddr(self: *Elf, decl: *const Module.Decl) u64 {425pub fn getDeclVAddr(self: *Elf, decl: *const Module.Decl, parent_atom_index: u32, offset: u64) !u64 {
403 assert(self.llvm_object == null);426 assert(self.llvm_object == null);
404 assert(decl.link.elf.local_sym_index != 0);427 assert(decl.link.elf.local_sym_index != 0);
405 return self.local_symbols.items[decl.link.elf.local_sym_index].st_value;428
429 const target = decl.link.elf.local_sym_index;
430 const vaddr = self.local_symbols.items[target].st_value;
431 const atom = self.atom_by_index_table.get(parent_atom_index).?;
432 const gop = try self.relocs.getOrPut(self.base.allocator, atom);
433 if (!gop.found_existing) {
434 gop.value_ptr.* = .{};
435 }
436 try gop.value_ptr.append(self.base.allocator, .{
437 .target = target,
438 .offset = offset,
439 .prev_vaddr = vaddr,
440 });
441
442 return vaddr;
406}443}
407444
408fn getDebugLineProgramOff(self: Elf) u32 {445fn getDebugLineProgramOff(self: Elf) u32 {
...@@ -991,6 +1028,41 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void {...@@ -991,6 +1028,41 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void {
991 .p64 => 12,1028 .p64 => 12,
992 };1029 };
9931030
1031 {
1032 var it = self.relocs.iterator();
1033 while (it.next()) |entry| {
1034 const atom = entry.key_ptr.*;
1035 const relocs = entry.value_ptr.*;
1036 const source_sym = self.local_symbols.items[atom.local_sym_index];
1037 const source_shdr = self.sections.items[source_sym.st_shndx];
1038
1039 log.debug("relocating '{s}'", .{self.getString(source_sym.st_name)});
1040
1041 for (relocs.items) |*reloc| {
1042 const target_sym = self.local_symbols.items[reloc.target];
1043 const target_vaddr = target_sym.st_value;
1044
1045 if (target_vaddr == reloc.prev_vaddr) continue;
1046
1047 const section_offset = (source_sym.st_value + reloc.offset) - source_shdr.sh_addr;
1048 const file_offset = source_shdr.sh_offset + section_offset;
1049
1050 log.debug(" ({x}: [() => 0x{x}] ({s}))", .{
1051 reloc.offset,
1052 target_vaddr,
1053 self.getString(target_sym.st_name),
1054 });
1055
1056 switch (self.ptr_width) {
1057 .p32 => try self.base.file.?.pwriteAll(mem.asBytes(&@intCast(u32, target_vaddr)), file_offset),
1058 .p64 => try self.base.file.?.pwriteAll(mem.asBytes(&target_vaddr), file_offset),
1059 }
1060
1061 reloc.prev_vaddr = target_vaddr;
1062 }
1063 }
1064 }
1065
994 // Unfortunately these have to be buffered and done at the end because ELF does not allow1066 // Unfortunately these have to be buffered and done at the end because ELF does not allow
995 // mixing local and global symbols within a symbol table.1067 // mixing local and global symbols within a symbol table.
996 try self.writeAllGlobalSymbols();1068 try self.writeAllGlobalSymbols();
...@@ -2508,6 +2580,7 @@ pub fn allocateDeclIndexes(self: *Elf, decl: *Module.Decl) !void {...@@ -2508,6 +2580,7 @@ pub fn allocateDeclIndexes(self: *Elf, decl: *Module.Decl) !void {
25082580
2509 log.debug("allocating symbol indexes for {s}", .{decl.name});2581 log.debug("allocating symbol indexes for {s}", .{decl.name});
2510 decl.link.elf.local_sym_index = try self.allocateLocalSymbol();2582 decl.link.elf.local_sym_index = try self.allocateLocalSymbol();
2583 try self.atom_by_index_table.putNoClobber(self.base.allocator, decl.link.elf.local_sym_index, &decl.link.elf);
25112584
2512 if (self.offset_table_free_list.popOrNull()) |i| {2585 if (self.offset_table_free_list.popOrNull()) |i| {
2513 decl.link.elf.offset_table_index = i;2586 decl.link.elf.offset_table_index = i;
...@@ -2525,6 +2598,7 @@ fn freeUnnamedConsts(self: *Elf, decl: *Module.Decl) void {...@@ -2525,6 +2598,7 @@ fn freeUnnamedConsts(self: *Elf, decl: *Module.Decl) void {
2525 self.freeTextBlock(atom, self.phdr_load_ro_index.?);2598 self.freeTextBlock(atom, self.phdr_load_ro_index.?);
2526 self.local_symbol_free_list.append(self.base.allocator, atom.local_sym_index) catch {};2599 self.local_symbol_free_list.append(self.base.allocator, atom.local_sym_index) catch {};
2527 self.local_symbols.items[atom.local_sym_index].st_info = 0;2600 self.local_symbols.items[atom.local_sym_index].st_info = 0;
2601 _ = self.atom_by_index_table.remove(atom.local_sym_index);
2528 }2602 }
2529 unnamed_consts.clearAndFree(self.base.allocator);2603 unnamed_consts.clearAndFree(self.base.allocator);
2530}2604}
...@@ -2543,11 +2617,11 @@ pub fn freeDecl(self: *Elf, decl: *Module.Decl) void {...@@ -2543,11 +2617,11 @@ pub fn freeDecl(self: *Elf, decl: *Module.Decl) void {
2543 // Appending to free lists is allowed to fail because the free lists are heuristics based anyway.2617 // Appending to free lists is allowed to fail because the free lists are heuristics based anyway.
2544 if (decl.link.elf.local_sym_index != 0) {2618 if (decl.link.elf.local_sym_index != 0) {
2545 self.local_symbol_free_list.append(self.base.allocator, decl.link.elf.local_sym_index) catch {};2619 self.local_symbol_free_list.append(self.base.allocator, decl.link.elf.local_sym_index) catch {};
2546 self.offset_table_free_list.append(self.base.allocator, decl.link.elf.offset_table_index) catch {};
2547
2548 self.local_symbols.items[decl.link.elf.local_sym_index].st_info = 0;2620 self.local_symbols.items[decl.link.elf.local_sym_index].st_info = 0;
25492621 _ = self.atom_by_index_table.remove(decl.link.elf.local_sym_index);
2550 decl.link.elf.local_sym_index = 0;2622 decl.link.elf.local_sym_index = 0;
2623
2624 self.offset_table_free_list.append(self.base.allocator, decl.link.elf.offset_table_index) catch {};
2551 }2625 }
2552 // TODO make this logic match freeTextBlock. Maybe abstract the logic out since the same thing2626 // TODO make this logic match freeTextBlock. Maybe abstract the logic out since the same thing
2553 // is desired for both.2627 // is desired for both.
...@@ -2993,7 +3067,7 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {...@@ -2993,7 +3067,7 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
29933067
2994 // TODO implement .debug_info for global variables3068 // TODO implement .debug_info for global variables
2995 const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val;3069 const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val;
2996 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{3070 const res = try codegen.generateSymbol(&self.base, decl.link.elf.local_sym_index, decl.srcLoc(), .{
2997 .ty = decl.ty,3071 .ty = decl.ty,
2998 .val = decl_val,3072 .val = decl_val,
2999 }, &code_buffer, .{3073 }, &code_buffer, .{
...@@ -3028,19 +3102,6 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl: *Module.Decl...@@ -3028,19 +3102,6 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl: *Module.Decl
3028 }3102 }
3029 const unnamed_consts = gop.value_ptr;3103 const unnamed_consts = gop.value_ptr;
30303104
3031 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), typed_value, &code_buffer, .{
3032 .none = .{},
3033 });
3034 const code = switch (res) {
3035 .externally_managed => |x| x,
3036 .appended => code_buffer.items,
3037 .fail => |em| {
3038 decl.analysis = .codegen_failure;
3039 try module.failed_decls.put(module.gpa, decl, em);
3040 return error.AnalysisFail;
3041 },
3042 };
3043
3044 const atom = try self.base.allocator.create(TextBlock);3105 const atom = try self.base.allocator.create(TextBlock);
3045 errdefer self.base.allocator.destroy(atom);3106 errdefer self.base.allocator.destroy(atom);
3046 atom.* = TextBlock.empty;3107 atom.* = TextBlock.empty;
...@@ -3056,6 +3117,20 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl: *Module.Decl...@@ -3056,6 +3117,20 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl: *Module.Decl
30563117
3057 log.debug("allocating symbol indexes for {s}", .{name});3118 log.debug("allocating symbol indexes for {s}", .{name});
3058 atom.local_sym_index = try self.allocateLocalSymbol();3119 atom.local_sym_index = try self.allocateLocalSymbol();
3120 try self.atom_by_index_table.putNoClobber(self.base.allocator, atom.local_sym_index, atom);
3121
3122 const res = try codegen.generateSymbol(&self.base, atom.local_sym_index, decl.srcLoc(), typed_value, &code_buffer, .{
3123 .none = .{},
3124 });
3125 const code = switch (res) {
3126 .externally_managed => |x| x,
3127 .appended => code_buffer.items,
3128 .fail => |em| {
3129 decl.analysis = .codegen_failure;
3130 try module.failed_decls.put(module.gpa, decl, em);
3131 return error.AnalysisFail;
3132 },
3133 };
30593134
3060 const required_alignment = typed_value.ty.abiAlignment(self.base.options.target);3135 const required_alignment = typed_value.ty.abiAlignment(self.base.options.target);
3061 const phdr_index = self.phdr_load_ro_index.?;3136 const phdr_index = self.phdr_load_ro_index.?;
src/link/MachO.zig+28-25
...@@ -3745,19 +3745,6 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl: *Module.De...@@ -3745,19 +3745,6 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl: *Module.De
3745 }3745 }
3746 const unnamed_consts = gop.value_ptr;3746 const unnamed_consts = gop.value_ptr;
37473747
3748 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), typed_value, &code_buffer, .{
3749 .none = .{},
3750 });
3751 const code = switch (res) {
3752 .externally_managed => |x| x,
3753 .appended => code_buffer.items,
3754 .fail => |em| {
3755 decl.analysis = .codegen_failure;
3756 try module.failed_decls.put(module.gpa, decl, em);
3757 return error.AnalysisFail;
3758 },
3759 };
3760
3761 const name_str_index = blk: {3748 const name_str_index = blk: {
3762 const index = unnamed_consts.items.len;3749 const index = unnamed_consts.items.len;
3763 const name = try std.fmt.allocPrint(self.base.allocator, "__unnamed_{s}_{d}", .{ decl.name, index });3750 const name = try std.fmt.allocPrint(self.base.allocator, "__unnamed_{s}_{d}", .{ decl.name, index });
...@@ -3772,12 +3759,27 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl: *Module.De...@@ -3772,12 +3759,27 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl: *Module.De
3772 const match = (try self.getMatchingSection(.{3759 const match = (try self.getMatchingSection(.{
3773 .segname = makeStaticString("__TEXT"),3760 .segname = makeStaticString("__TEXT"),
3774 .sectname = makeStaticString("__const"),3761 .sectname = makeStaticString("__const"),
3775 .size = code.len,3762 .size = @sizeOf(u64),
3776 .@"align" = math.log2(required_alignment),3763 .@"align" = math.log2(required_alignment),
3777 })).?;3764 })).?;
3778 const local_sym_index = try self.allocateLocalSymbol();3765 const local_sym_index = try self.allocateLocalSymbol();
3779 const atom = try self.createEmptyAtom(local_sym_index, code.len, math.log2(required_alignment));3766 const atom = try self.createEmptyAtom(local_sym_index, @sizeOf(u64), math.log2(required_alignment));
3780 mem.copy(u8, atom.code.items, code);3767
3768 const res = try codegen.generateSymbol(&self.base, local_sym_index, decl.srcLoc(), typed_value, &code_buffer, .{
3769 .none = .{},
3770 });
3771 const code = switch (res) {
3772 .externally_managed => |x| x,
3773 .appended => code_buffer.items,
3774 .fail => |em| {
3775 decl.analysis = .codegen_failure;
3776 try module.failed_decls.put(module.gpa, decl, em);
3777 return error.AnalysisFail;
3778 },
3779 };
3780
3781 atom.code.clearRetainingCapacity();
3782 try atom.code.appendSlice(self.base.allocator, code);
3781 const addr = try self.allocateAtom(atom, code.len, required_alignment, match);3783 const addr = try self.allocateAtom(atom, code.len, required_alignment, match);
37823784
3783 log.debug("allocated atom for {s} at 0x{x}", .{ name, addr });3785 log.debug("allocated atom for {s} at 0x{x}", .{ name, addr });
...@@ -3841,7 +3843,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {...@@ -3841,7 +3843,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
38413843
3842 const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val;3844 const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val;
3843 const res = if (debug_buffers) |dbg|3845 const res = if (debug_buffers) |dbg|
3844 try codegen.generateSymbol(&self.base, decl.srcLoc(), .{3846 try codegen.generateSymbol(&self.base, decl.link.elf.local_sym_index, decl.srcLoc(), .{
3845 .ty = decl.ty,3847 .ty = decl.ty,
3846 .val = decl_val,3848 .val = decl_val,
3847 }, &code_buffer, .{3849 }, &code_buffer, .{
...@@ -3852,7 +3854,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {...@@ -3852,7 +3854,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
3852 },3854 },
3853 })3855 })
3854 else3856 else
3855 try codegen.generateSymbol(&self.base, decl.srcLoc(), .{3857 try codegen.generateSymbol(&self.base, decl.link.elf.local_sym_index, decl.srcLoc(), .{
3856 .ty = decl.ty,3858 .ty = decl.ty,
3857 .val = decl_val,3859 .val = decl_val,
3858 }, &code_buffer, .none);3860 }, &code_buffer, .none);
...@@ -4341,16 +4343,17 @@ pub fn freeDecl(self: *MachO, decl: *Module.Decl) void {...@@ -4341,16 +4343,17 @@ pub fn freeDecl(self: *MachO, decl: *Module.Decl) void {
4341 }4343 }
4342}4344}
43434345
4344pub fn getDeclVAddr(self: *MachO, decl: *const Module.Decl) u64 {4346pub fn getDeclVAddr(self: *MachO, decl: *const Module.Decl, parent_atom_index: u32, offset: u64) !u64 {
4347 assert(self.llvm_object == null);
4345 assert(decl.link.macho.local_sym_index != 0);4348 assert(decl.link.macho.local_sym_index != 0);
4346 return self.locals.items[decl.link.macho.local_sym_index].n_value;
4347}
43484349
4349pub fn getDeclVAddrWithReloc(self: *MachO, decl: *const Module.Decl, offset: u64) !u64 {4350 // TODO cache local_sym_index => atom!!!
4350 assert(decl.link.macho.local_sym_index != 0);4351 const atom: *Atom = blk: for (self.managed_atoms.items) |atom| {
4351 assert(self.active_decl != null);4352 if (atom.local_sym_index == parent_atom_index) {
4353 break :blk atom;
4354 }
4355 } else unreachable;
43524356
4353 const atom = &self.active_decl.?.link.macho;
4354 try atom.relocs.append(self.base.allocator, .{4357 try atom.relocs.append(self.base.allocator, .{
4355 .offset = @intCast(u32, offset),4358 .offset = @intCast(u32, offset),
4356 .target = .{ .local = decl.link.macho.local_sym_index },4359 .target = .{ .local = decl.link.macho.local_sym_index },
src/link/Plan9.zig+4-2
...@@ -302,7 +302,7 @@ pub fn updateDecl(self: *Plan9, module: *Module, decl: *Module.Decl) !void {...@@ -302,7 +302,7 @@ pub fn updateDecl(self: *Plan9, module: *Module, decl: *Module.Decl) !void {
302 var code_buffer = std.ArrayList(u8).init(self.base.allocator);302 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
303 defer code_buffer.deinit();303 defer code_buffer.deinit();
304 const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val;304 const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val;
305 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{305 const res = try codegen.generateSymbol(&self.base, @intCast(u32, decl.link.plan9.sym_index.?), decl.srcLoc(), .{
306 .ty = decl.ty,306 .ty = decl.ty,
307 .val = decl_val,307 .val = decl_val,
308 }, &code_buffer, .{ .none = .{} });308 }, &code_buffer, .{ .none = .{} });
...@@ -749,7 +749,9 @@ pub fn allocateDeclIndexes(self: *Plan9, decl: *Module.Decl) !void {...@@ -749,7 +749,9 @@ pub fn allocateDeclIndexes(self: *Plan9, decl: *Module.Decl) !void {
749 _ = self;749 _ = self;
750 _ = decl;750 _ = decl;
751}751}
752pub fn getDeclVAddr(self: *Plan9, decl: *const Module.Decl) u64 {752pub fn getDeclVAddr(self: *Plan9, decl: *const Module.Decl, parent_atom_index: u32, offset: u64) !u64 {
753 _ = parent_atom_index;
754 _ = offset;
753 if (decl.ty.zigTypeTag() == .Fn) {755 if (decl.ty.zigTypeTag() == .Fn) {
754 var start = self.bases.text;756 var start = self.bases.text;
755 var it_file = self.fn_decl_table.iterator();757 var it_file = self.fn_decl_table.iterator();