From f8dd48bcd257a5a6a893c11b89af21b7e2ca9a79 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Wed, 30 Sep 2020 23:17:40 +0200 Subject: Fix after rebase and enable stage2 tests for macOS Also, rewrites codegen section to store symbol address in a register to then later invoke `callq` on the register. --- src/codegen.zig | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src/codegen.zig') diff --git a/src/codegen.zig b/src/codegen.zig index a1d3cc2fc4..919d1ef457 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -1532,12 +1532,12 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { if (func_inst.val.cast(Value.Payload.Function)) |func_val| { const func = func_val.func; const got = &macho_file.sections.items[macho_file.got_section_index.?]; - const ptr_bytes = 8; - const got_addr = @intCast(u32, got.addr + func.owner_decl.link.macho.offset_table_index.? * ptr_bytes); - // ff 14 25 xx xx xx xx call [addr] - try self.code.ensureCapacity(self.code.items.len + 7); - self.code.appendSliceAssumeCapacity(&[3]u8{ 0xff, 0x14, 0x25 }); - mem.writeIntLittle(u32, self.code.addManyAsArrayAssumeCapacity(4), got_addr); + const got_addr = got.addr + func.owner_decl.link.macho.offset_table_index.? * @sizeOf(u64); + // Here, we store the got address in %rax, and then call %rax + // movabsq [addr], %rax + try self.genSetReg(inst.base.src, .rax, .{ .memory = got_addr }); + // callq *%rax + self.code.appendSliceAssumeCapacity(&[2]u8{ 0xff, 0xd0 }); } else { return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{}); } -- cgit v1.2.3 From 2ba23abd9d267f6e007df1661da32be583145a6b Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Thu, 1 Oct 2020 19:59:05 +0200 Subject: Add missing ensureCapacity call in codegen --- src/codegen.zig | 1 + 1 file changed, 1 insertion(+) (limited to 'src/codegen.zig') diff --git a/src/codegen.zig b/src/codegen.zig index 919d1ef457..ccd1bc3b22 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -1537,6 +1537,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { // movabsq [addr], %rax try self.genSetReg(inst.base.src, .rax, .{ .memory = got_addr }); // callq *%rax + try self.code.ensureCapacity(self.code.items.len + 2); self.code.appendSliceAssumeCapacity(&[2]u8{ 0xff, 0xd0 }); } else { return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{}); -- cgit v1.2.3 From 737a8bf2041158b3036bda9130f9ce3f6c1ad582 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Thu, 1 Oct 2020 20:20:01 +0200 Subject: Redo local symbols and offsets tracking to match Elf's approach --- src/codegen.zig | 4 +-- src/link/MachO.zig | 74 +++++++++++++++++++++++++++++++++--------------------- 2 files changed, 48 insertions(+), 30 deletions(-) (limited to 'src/codegen.zig') diff --git a/src/codegen.zig b/src/codegen.zig index ccd1bc3b22..57d2f8ff1f 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -1532,7 +1532,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { if (func_inst.val.cast(Value.Payload.Function)) |func_val| { const func = func_val.func; const got = &macho_file.sections.items[macho_file.got_section_index.?]; - const got_addr = got.addr + func.owner_decl.link.macho.offset_table_index.? * @sizeOf(u64); + const got_addr = got.addr + func.owner_decl.link.macho.offset_table_index * @sizeOf(u64); // Here, we store the got address in %rax, and then call %rax // movabsq [addr], %rax try self.genSetReg(inst.base.src, .rax, .{ .memory = got_addr }); @@ -2591,7 +2591,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { const decl = payload.decl; const got = &macho_file.sections.items[macho_file.got_section_index.?]; - const got_addr = got.addr + decl.link.macho.offset_table_index.? * ptr_bytes; + const got_addr = got.addr + decl.link.macho.offset_table_index * ptr_bytes; return MCValue{ .memory = got_addr }; } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { const decl = payload.decl; diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 9a58a35dc9..040e475c2c 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -149,19 +149,27 @@ const LIB_SYSTEM_NAME: [*:0]const u8 = "System"; const LIB_SYSTEM_PATH: [*:0]const u8 = DEFAULT_LIB_SEARCH_PATH ++ "/libSystem.B.dylib"; pub const TextBlock = struct { - /// Index into the symbol table - symbol_table_index: ?u32, + /// Each decl always gets a local symbol with the fully qualified name. + /// The vaddr and size are found here directly. + /// The file offset is found by computing the vaddr offset from the section vaddr + /// the symbol references, and adding that to the file offset of the section. + /// If this field is 0, it means the codegen size = 0 and there is no symbol or + /// offset table entry. + local_sym_index: u32, /// Index into offset table - offset_table_index: ?u32, + /// This field is undefined for symbols with size = 0. + offset_table_index: u32, /// Size of this text block + /// Unlike in Elf, we need to store the size of this symbol as part of + /// the TextBlock since macho.nlist_64 lacks this information. size: u64, /// Points to the previous and next neighbours prev: ?*TextBlock, next: ?*TextBlock, pub const empty = TextBlock{ - .symbol_table_index = null, - .offset_table_index = null, + .local_sym_index = 0, + .offset_table_index = undefined, .size = 0, .prev = null, .next = null, @@ -190,6 +198,15 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio self.base.file = file; + // Index 0 is always a null symbol. + try self.local_symbols.append(allocator, .{ + .n_strx = 0, + .n_type = 0, + .n_sect = 0, + .n_desc = 0, + .n_value = 0, + }); + switch (options.output_mode) { .Exe => {}, .Obj => {}, @@ -717,26 +734,26 @@ pub fn deinit(self: *MachO) void { } pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void { - if (decl.link.macho.symbol_table_index) |_| return; + if (decl.link.macho.local_sym_index != 0) return; try self.local_symbols.ensureCapacity(self.base.allocator, self.local_symbols.items.len + 1); try self.offset_table.ensureCapacity(self.base.allocator, self.offset_table.items.len + 1); log.debug("allocating symbol index {} for {}\n", .{ self.local_symbols.items.len, decl.name }); - decl.link.macho.symbol_table_index = @intCast(u32, self.local_symbols.items.len); + decl.link.macho.local_sym_index = @intCast(u32, self.local_symbols.items.len); _ = self.local_symbols.addOneAssumeCapacity(); decl.link.macho.offset_table_index = @intCast(u32, self.offset_table.items.len); _ = self.offset_table.addOneAssumeCapacity(); - self.local_symbols.items[decl.link.macho.symbol_table_index.?] = .{ + self.local_symbols.items[decl.link.macho.local_sym_index] = .{ .n_strx = 0, .n_type = 0, .n_sect = 0, .n_desc = 0, .n_value = 0, }; - self.offset_table.items[decl.link.macho.offset_table_index.?] = 0; + self.offset_table.items[decl.link.macho.offset_table_index] = 0; } pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { @@ -761,7 +778,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { log.debug("generated code {}\n", .{code}); const required_alignment = typed_value.ty.abiAlignment(self.base.options.target); - const symbol = &self.local_symbols.items[decl.link.macho.symbol_table_index.?]; + const symbol = &self.local_symbols.items[decl.link.macho.local_sym_index]; const decl_name = mem.spanZ(decl.name); const name_str_index = try self.makeString(decl_name); @@ -776,10 +793,10 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { .n_desc = 0, .n_value = addr, }; - self.offset_table.items[decl.link.macho.offset_table_index.?] = addr; + self.offset_table.items[decl.link.macho.offset_table_index] = addr; - try self.writeSymbol(decl.link.macho.symbol_table_index.?); - try self.writeOffsetTableEntry(decl.link.macho.offset_table_index.?); + try self.writeSymbol(decl.link.macho.local_sym_index); + try self.writeOffsetTableEntry(decl.link.macho.offset_table_index); const text_section = self.sections.items[self.text_section_index.?]; const section_offset = symbol.n_value - text_section.addr; @@ -805,8 +822,8 @@ pub fn updateDeclExports( defer tracy.end(); try self.global_symbols.ensureCapacity(self.base.allocator, self.global_symbols.items.len + exports.len); - if (decl.link.macho.symbol_table_index == null) return; - const decl_sym = &self.local_symbols.items[decl.link.macho.symbol_table_index.?]; + if (decl.link.macho.local_sym_index == 0) return; + const decl_sym = &self.local_symbols.items[decl.link.macho.local_sym_index]; for (exports) |exp| { if (exp.options.section) |section_name| { @@ -867,7 +884,8 @@ pub fn updateDeclExports( pub fn freeDecl(self: *MachO, decl: *Module.Decl) void {} pub fn getDeclVAddr(self: *MachO, decl: *const Module.Decl) u64 { - return self.local_symbols.items[decl.link.macho.symbol_table_index.?].n_value; + assert(decl.link.macho.local_sym_index != 0); + return self.local_symbols.items[decl.link.macho.local_sym_index].n_value; } pub fn populateMissingMetadata(self: *MachO) !void { @@ -1126,17 +1144,6 @@ pub fn populateMissingMetadata(self: *MachO) !void { }); self.cmd_table_dirty = true; } - if (self.dyld_stub_binder_index == null) { - self.dyld_stub_binder_index = @intCast(u16, self.undef_symbols.items.len); - const name = try self.makeString("dyld_stub_binder"); - try self.undef_symbols.append(self.base.allocator, .{ - .n_strx = name, - .n_type = macho.N_UNDF | macho.N_EXT, - .n_sect = 0, - .n_desc = macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY | macho.N_SYMBOL_RESOLVER, - .n_value = 0, - }); - } { const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfo; @@ -1175,6 +1182,17 @@ pub fn populateMissingMetadata(self: *MachO) !void { symtab.strsize = file_size; } } + if (self.dyld_stub_binder_index == null) { + self.dyld_stub_binder_index = @intCast(u16, self.undef_symbols.items.len); + const name = try self.makeString("dyld_stub_binder"); + try self.undef_symbols.append(self.base.allocator, .{ + .n_strx = name, + .n_type = macho.N_UNDF | macho.N_EXT, + .n_sect = 0, + .n_desc = macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY | macho.N_SYMBOL_RESOLVER, + .n_value = 0, + }); + } } fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 { @@ -1184,7 +1202,7 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, var block_placement: ?*TextBlock = null; const addr = blk: { if (self.last_text_block) |last| { - const last_symbol = self.local_symbols.items[last.symbol_table_index.?]; + const last_symbol = self.local_symbols.items[last.local_sym_index]; // TODO pad out with NOPs and reenable // const ideal_capacity = last.size * alloc_num / alloc_den; // const ideal_capacity_end_addr = last_symbol.n_value + ideal_capacity; -- cgit v1.2.3