diff --git a/src/arch/riscv64/Emit.zig b/src/arch/riscv64/Emit.zig index a4fadad526..258941f19d 100644 --- a/src/arch/riscv64/Emit.zig +++ b/src/arch/riscv64/Emit.zig @@ -56,17 +56,17 @@ pub fn emitMir(emit: *Emit) Error!void { const hi_r_type: u32 = @intFromEnum(std.elf.R_RISCV.HI20); const lo_r_type: u32 = @intFromEnum(std.elf.R_RISCV.LO12_I); - try atom_ptr.addReloc(elf_file, .{ + try atom_ptr.addReloc(elf_file.base.comp.gpa, .{ .r_offset = start_offset, .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | hi_r_type, .r_addend = 0, - }); + }, zo); - try atom_ptr.addReloc(elf_file, .{ + try atom_ptr.addReloc(elf_file.base.comp.gpa, .{ .r_offset = start_offset + 4, .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | lo_r_type, .r_addend = 0, - }); + }, zo); }, .load_tlv_reloc => |symbol| { const elf_file = emit.bin_file.cast(.elf).?; @@ -76,23 +76,23 @@ pub fn emitMir(emit: *Emit) Error!void { const R_RISCV = std.elf.R_RISCV; - try atom_ptr.addReloc(elf_file, .{ + try atom_ptr.addReloc(elf_file.base.comp.gpa, .{ .r_offset = start_offset, .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | @intFromEnum(R_RISCV.TPREL_HI20), .r_addend = 0, - }); + }, zo); - try atom_ptr.addReloc(elf_file, .{ + try atom_ptr.addReloc(elf_file.base.comp.gpa, .{ .r_offset = start_offset + 4, .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | @intFromEnum(R_RISCV.TPREL_ADD), .r_addend = 0, - }); + }, zo); - try atom_ptr.addReloc(elf_file, .{ + try atom_ptr.addReloc(elf_file.base.comp.gpa, .{ .r_offset = start_offset + 8, .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | @intFromEnum(R_RISCV.TPREL_LO12_I), .r_addend = 0, - }); + }, zo); }, .call_extern_fn_reloc => |symbol| { const elf_file = emit.bin_file.cast(.elf).?; @@ -101,11 +101,11 @@ pub fn emitMir(emit: *Emit) Error!void { const r_type: u32 = @intFromEnum(std.elf.R_RISCV.CALL_PLT); - try atom_ptr.addReloc(elf_file, .{ + try atom_ptr.addReloc(elf_file.base.comp.gpa, .{ .r_offset = start_offset, .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | r_type, .r_addend = 0, - }); + }, zo); }, }; } diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig index 579fd00d9d..9fce779862 100644 --- a/src/arch/x86_64/Emit.zig +++ b/src/arch/x86_64/Emit.zig @@ -48,11 +48,11 @@ pub fn emitMir(emit: *Emit) Error!void { const zo = elf_file.zigObjectPtr().?; const atom_ptr = zo.symbol(emit.atom_index).atom(elf_file).?; const r_type = @intFromEnum(std.elf.R_X86_64.PLT32); - try atom_ptr.addReloc(elf_file, .{ + try atom_ptr.addReloc(elf_file.base.comp.gpa, .{ .r_offset = end_offset - 4, .r_info = (@as(u64, @intCast(sym_index)) << 32) | r_type, .r_addend = lowered_relocs[0].off - 4, - }); + }, zo); } else if (emit.lower.bin_file.cast(.macho)) |macho_file| { // Add relocation to the decl. const zo = macho_file.getZigObject().?; @@ -95,22 +95,22 @@ pub fn emitMir(emit: *Emit) Error!void { const zo = elf_file.zigObjectPtr().?; const atom = zo.symbol(emit.atom_index).atom(elf_file).?; const r_type = @intFromEnum(std.elf.R_X86_64.TLSLD); - try atom.addReloc(elf_file, .{ + try atom.addReloc(elf_file.base.comp.gpa, .{ .r_offset = end_offset - 4, .r_info = (@as(u64, @intCast(sym_index)) << 32) | r_type, .r_addend = lowered_relocs[0].off - 4, - }); + }, zo); }, .linker_dtpoff => |sym_index| { const elf_file = emit.lower.bin_file.cast(.elf).?; const zo = elf_file.zigObjectPtr().?; const atom = zo.symbol(emit.atom_index).atom(elf_file).?; const r_type = @intFromEnum(std.elf.R_X86_64.DTPOFF32); - try atom.addReloc(elf_file, .{ + try atom.addReloc(elf_file.base.comp.gpa, .{ .r_offset = end_offset - 4, .r_info = (@as(u64, @intCast(sym_index)) << 32) | r_type, .r_addend = lowered_relocs[0].off, - }); + }, zo); }, .linker_reloc => |sym_index| if (emit.lower.bin_file.cast(.elf)) |elf_file| { const zo = elf_file.zigObjectPtr().?; @@ -121,21 +121,21 @@ pub fn emitMir(emit: *Emit) Error!void { @intFromEnum(std.elf.R_X86_64.GOTPCREL) else @intFromEnum(std.elf.R_X86_64.PC32); - try atom.addReloc(elf_file, .{ + try atom.addReloc(elf_file.base.comp.gpa, .{ .r_offset = end_offset - 4, .r_info = (@as(u64, @intCast(sym_index)) << 32) | r_type, .r_addend = lowered_relocs[0].off - 4, - }); + }, zo); } else { const r_type: u32 = if (sym.flags.is_tls) @intFromEnum(std.elf.R_X86_64.TPOFF32) else @intFromEnum(std.elf.R_X86_64.@"32"); - try atom.addReloc(elf_file, .{ + try atom.addReloc(elf_file.base.comp.gpa, .{ .r_offset = end_offset - 4, .r_info = (@as(u64, @intCast(sym_index)) << 32) | r_type, .r_addend = lowered_relocs[0].off, - }); + }, zo); } } else if (emit.lower.bin_file.cast(.macho)) |macho_file| { const zo = macho_file.getZigObject().?; diff --git a/src/link/Elf/Atom.zig b/src/link/Elf/Atom.zig index a9050dcd00..3eb447ab75 100644 --- a/src/link/Elf/Atom.zig +++ b/src/link/Elf/Atom.zig @@ -302,7 +302,7 @@ pub fn free(self: *Atom, elf_file: *Elf) void { } // TODO create relocs free list - self.freeRelocs(elf_file); + self.freeRelocs(zo); // TODO figure out how to free input section mappind in ZigModule // const zig_object = elf_file.zigObjectPtr().? // assert(zig_object.atoms.swapRemove(self.atom_index)); @@ -377,21 +377,19 @@ pub fn markFdesDead(self: Atom, elf_file: *Elf) void { } } -pub fn addReloc(self: Atom, elf_file: *Elf, reloc: elf.Elf64_Rela) !void { - const comp = elf_file.base.comp; - const gpa = comp.gpa; - const file_ptr = self.file(elf_file).?; - assert(file_ptr == .zig_object); - const zig_object = file_ptr.zig_object; - const rels = &zig_object.relocs.items[self.relocs_section_index]; - try rels.append(gpa, reloc); +pub fn addReloc(self: Atom, alloc: Allocator, reloc: elf.Elf64_Rela, zo: *ZigObject) !void { + const rels = &zo.relocs.items[self.relocs_section_index]; + try rels.ensureUnusedCapacity(alloc, 1); + self.addRelocAssumeCapacity(reloc, zo); } -pub fn freeRelocs(self: Atom, elf_file: *Elf) void { - const file_ptr = self.file(elf_file).?; - assert(file_ptr == .zig_object); - const zig_object = file_ptr.zig_object; - zig_object.relocs.items[self.relocs_section_index].clearRetainingCapacity(); +pub fn addRelocAssumeCapacity(self: Atom, reloc: elf.Elf64_Rela, zo: *ZigObject) void { + const rels = &zo.relocs.items[self.relocs_section_index]; + rels.appendAssumeCapacity(reloc); +} + +pub fn freeRelocs(self: Atom, zo: *ZigObject) void { + zo.relocs.items[self.relocs_section_index].clearRetainingCapacity(); } pub fn scanRelocsRequiresCode(self: Atom, elf_file: *Elf) bool { diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index 28cc84da35..18eb047b0b 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -182,6 +182,8 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi try dwarf.flushModule(pt); try dwarf.resolveRelocs(); + const gpa = elf_file.base.comp.gpa; + // TODO invert this logic so that we manage the output section with the atom, not the // other way around for ([_]u32{ @@ -206,24 +208,47 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi const sym = self.symbol(sym_index); const atom_ptr = self.atom(sym.ref.index).?; if (!atom_ptr.alive) continue; - const shdr = elf_file.shdrs.items[sym.outputShndx(elf_file).?]; + const shndx = sym.outputShndx(elf_file).?; + const shdr = elf_file.shdrs.items[shndx]; const esym = &self.symtab.items(.elf_sym)[sym.esym_index]; esym.st_size = shdr.sh_size; atom_ptr.size = shdr.sh_size; atom_ptr.alignment = Atom.Alignment.fromNonzeroByteUnits(shdr.sh_addralign); const relocs = &self.relocs.items[atom_ptr.relocsShndx().?]; - _ = relocs; for (sect.units.items) |*unit| { + try relocs.ensureUnusedCapacity(gpa, unit.external_relocs.items.len); for (unit.external_relocs.items) |reloc| { const tsym = self.symbol(reloc.target_sym); const r_offset = unit.off + unit.header_len + unit.getEntry(reloc.source_entry).off + reloc.source_off; - const r_addend = reloc.target_off; - std.debug.print("{s} <- r_off={x}, r_add={x}\n", .{ + const r_addend: i64 = @intCast(reloc.target_off); + const r_type: elf.R_X86_64 = switch (dwarf.address_size) { + .@"32" => .@"32", + .@"64" => .@"64", + else => unreachable, + }; + log.debug("{s} <- r_off={x}, r_add={x}, r_type={s}\n", .{ tsym.name(elf_file), r_offset, r_addend, + @tagName(r_type), }); + atom_ptr.addRelocAssumeCapacity(.{ + .r_offset = r_offset, + .r_addend = r_addend, + .r_info = (@as(u64, @intCast(reloc.target_sym)) << 32) | @intFromEnum(r_type), + }, self); + } + } + + if (elf_file.base.isRelocatable() and relocs.items.len > 0) { + const gop = try elf_file.output_rela_sections.getOrPut(gpa, shndx); + if (!gop.found_existing) { + const rela_sect_name = try std.fmt.allocPrintZ(gpa, ".rela{s}", .{elf_file.getShString(shdr.sh_name)}); + defer gpa.free(rela_sect_name); + const rela_sh_name = try elf_file.insertShString(rela_sect_name); + const rela_shndx = try elf_file.addRelaShdr(rela_sh_name, shndx); + gop.value_ptr.* = .{ .shndx = rela_shndx }; } } } @@ -698,11 +723,11 @@ pub fn getNavVAddr( const vaddr = this_sym.address(.{}, elf_file); const parent_atom = self.symbol(reloc_info.parent_atom_index).atom(elf_file).?; const r_type = relocation.encode(.abs, elf_file.getTarget().cpu.arch); - try parent_atom.addReloc(elf_file, .{ + try parent_atom.addReloc(elf_file.base.comp.gpa, .{ .r_offset = reloc_info.offset, .r_info = (@as(u64, @intCast(this_sym_index)) << 32) | r_type, .r_addend = reloc_info.addend, - }); + }, self); return @intCast(vaddr); } @@ -717,11 +742,11 @@ pub fn getUavVAddr( const vaddr = sym.address(.{}, elf_file); const parent_atom = self.symbol(reloc_info.parent_atom_index).atom(elf_file).?; const r_type = relocation.encode(.abs, elf_file.getTarget().cpu.arch); - try parent_atom.addReloc(elf_file, .{ + try parent_atom.addReloc(elf_file.base.comp.gpa, .{ .r_offset = reloc_info.offset, .r_info = (@as(u64, @intCast(sym_index)) << 32) | r_type, .r_addend = reloc_info.addend, - }); + }, self); return @intCast(vaddr); } @@ -1068,7 +1093,7 @@ pub fn updateFunc( log.debug("updateFunc {}({d})", .{ ip.getNav(func.owner_nav).fqn.fmt(ip), func.owner_nav }); const sym_index = try self.getOrCreateMetadataForNav(elf_file, func.owner_nav); - self.symbol(sym_index).atom(elf_file).?.freeRelocs(elf_file); + self.symbol(sym_index).atom(elf_file).?.freeRelocs(self); var code_buffer = std.ArrayList(u8).init(gpa); defer code_buffer.deinit(); @@ -1196,7 +1221,7 @@ pub fn updateNav( if (nav_init != .none and Value.fromInterned(nav_init).typeOf(zcu).hasRuntimeBits(pt)) { const sym_index = try self.getOrCreateMetadataForNav(elf_file, nav_index); - self.symbol(sym_index).atom(elf_file).?.freeRelocs(elf_file); + self.symbol(sym_index).atom(elf_file).?.freeRelocs(self); var code_buffer = std.ArrayList(u8).init(zcu.gpa); defer code_buffer.deinit();