| author | |
| committer | |
| log | fcafaae747c0d032401ca7936b667f5dfcf0466b |
| tree | bfbf921a30a4cf275aaabb4012429e72709687e4 |
| parent | 004d0c8978d4b5e4212c06abb33d7a594930f8c5 |
| signature |
7 files changed, 128 insertions(+), 34 deletions(-)
src/arch/riscv64/CodeGen.zig+32-11| ... | @@ -3590,22 +3590,42 @@ fn genCall( | ... | @@ -3590,22 +3590,42 @@ fn genCall( |
| 3590 | const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func.owner_decl); | 3590 | const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func.owner_decl); |
| 3591 | const sym = elf_file.symbol(sym_index); | 3591 | const sym = elf_file.symbol(sym_index); |
| 3592 | 3592 | ||
| 3593 | _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file); | 3593 | if (self.mod.pic) { |
| 3594 | const got_addr = sym.zigGotAddress(elf_file); | 3594 | return self.fail("TODO: genCall pic", .{}); |
| 3595 | try self.genSetReg(Type.usize, .ra, .{ .memory = @intCast(got_addr) }); | 3595 | } else { |
| 3596 | _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file); | ||
| 3597 | const got_addr = sym.zigGotAddress(elf_file); | ||
| 3598 | try self.genSetReg(Type.usize, .ra, .{ .memory = @intCast(got_addr) }); | ||
| 3599 | |||
| 3600 | _ = try self.addInst(.{ | ||
| 3601 | .tag = .jalr, | ||
| 3602 | .ops = .rri, | ||
| 3603 | .data = .{ .i_type = .{ | ||
| 3604 | .rd = .ra, | ||
| 3605 | .rs1 = .ra, | ||
| 3606 | .imm12 = Immediate.s(0), | ||
| 3607 | } }, | ||
| 3608 | }); | ||
| 3609 | } | ||
| 3610 | } else unreachable; // not a valid riscv64 format | ||
| 3611 | }, | ||
| 3612 | .extern_func => |extern_func| { | ||
| 3613 | const owner_decl = zcu.declPtr(extern_func.decl); | ||
| 3614 | const lib_name = extern_func.lib_name.toSlice(&zcu.intern_pool); | ||
| 3615 | const decl_name = owner_decl.name.toSlice(&zcu.intern_pool); | ||
| 3616 | const atom_index = try self.symbolIndex(); | ||
| 3596 | 3617 | ||
| 3618 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { | ||
| 3597 | _ = try self.addInst(.{ | 3619 | _ = try self.addInst(.{ |
| 3598 | .tag = .jalr, | 3620 | .tag = .pseudo, |
| 3599 | .ops = .rri, | 3621 | .ops = .pseudo_extern_fn_reloc, |
| 3600 | .data = .{ .i_type = .{ | 3622 | .data = .{ .reloc = .{ |
| 3601 | .rd = .ra, | 3623 | .atom_index = atom_index, |
| 3602 | .rs1 = .ra, | 3624 | .sym_index = try elf_file.getGlobalSymbol(decl_name, lib_name), |
| 3603 | .imm12 = Immediate.s(0), | ||
| 3604 | } }, | 3625 | } }, |
| 3605 | }); | 3626 | }); |
| 3606 | } else unreachable; | 3627 | } else unreachable; // not a valid riscv64 format |
| 3607 | }, | 3628 | }, |
| 3608 | .extern_func => return self.fail("TODO: extern func calls", .{}), | ||
| 3609 | else => return self.fail("TODO implement calling bitcasted functions", .{}), | 3629 | else => return self.fail("TODO implement calling bitcasted functions", .{}), |
| 3610 | } | 3630 | } |
| 3611 | } else { | 3631 | } else { |
| ... | @@ -3613,6 +3633,7 @@ fn genCall( | ... | @@ -3613,6 +3633,7 @@ fn genCall( |
| 3613 | const addr_reg, const addr_lock = try self.allocReg(); | 3633 | const addr_reg, const addr_lock = try self.allocReg(); |
| 3614 | defer self.register_manager.unlockReg(addr_lock); | 3634 | defer self.register_manager.unlockReg(addr_lock); |
| 3615 | try self.genSetReg(Type.usize, addr_reg, .{ .air_ref = callee }); | 3635 | try self.genSetReg(Type.usize, addr_reg, .{ .air_ref = callee }); |
| 3636 | |||
| 3616 | _ = try self.addInst(.{ | 3637 | _ = try self.addInst(.{ |
| 3617 | .tag = .jalr, | 3638 | .tag = .jalr, |
| 3618 | .ops = .rri, | 3639 | .ops = .rri, |
src/arch/riscv64/Emit.zig+13| ... | @@ -70,6 +70,19 @@ pub fn emitMir(emit: *Emit) Error!void { | ... | @@ -70,6 +70,19 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 70 | }); | 70 | }); |
| 71 | } else return emit.fail("TODO: load_symbol_reloc non-ELF", .{}); | 71 | } else return emit.fail("TODO: load_symbol_reloc non-ELF", .{}); |
| 72 | }, | 72 | }, |
| 73 | .call_extern_fn_reloc => |symbol| { | ||
| 74 | if (emit.lower.bin_file.cast(link.File.Elf)) |elf_file| { | ||
| 75 | const atom_ptr = elf_file.symbol(symbol.atom_index).atom(elf_file).?; | ||
| 76 | |||
| 77 | const r_type: u32 = @intFromEnum(std.elf.R_RISCV.CALL_PLT); | ||
| 78 | |||
| 79 | try atom_ptr.addReloc(elf_file, .{ | ||
| 80 | .r_offset = start_offset, | ||
| 81 | .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | r_type, | ||
| 82 | .r_addend = 0, | ||
| 83 | }); | ||
| 84 | } else return emit.fail("TODO: call_extern_fn_reloc non-ELF", .{}); | ||
| 85 | }, | ||
| 73 | }; | 86 | }; |
| 74 | } | 87 | } |
| 75 | std.debug.assert(lowered_relocs.len == 0); | 88 | std.debug.assert(lowered_relocs.len == 0); |
src/arch/riscv64/Encoding.zig+3| ... | @@ -22,6 +22,7 @@ pub const Mnemonic = enum { | ... | @@ -22,6 +22,7 @@ pub const Mnemonic = enum { |
| 22 | 22 | ||
| 23 | // U Type | 23 | // U Type |
| 24 | lui, | 24 | lui, |
| 25 | auipc, | ||
| 25 | 26 | ||
| 26 | // S Type | 27 | // S Type |
| 27 | sd, | 28 | sd, |
| ... | @@ -78,6 +79,7 @@ pub const Mnemonic = enum { | ... | @@ -78,6 +79,7 @@ pub const Mnemonic = enum { |
| 78 | .srai => .{ .opcode = 0b0010011, .funct3 = 0b101, .funct7 = null, .offset = 1 << 10 }, | 79 | .srai => .{ .opcode = 0b0010011, .funct3 = 0b101, .funct7 = null, .offset = 1 << 10 }, |
| 79 | 80 | ||
| 80 | .lui => .{ .opcode = 0b0110111, .funct3 = null, .funct7 = null }, | 81 | .lui => .{ .opcode = 0b0110111, .funct3 = null, .funct7 = null }, |
| 82 | .auipc => .{ .opcode = 0b0010111, .funct3 = null, .funct7 = null }, | ||
| 81 | 83 | ||
| 82 | .sd => .{ .opcode = 0b0100011, .funct3 = 0b011, .funct7 = null }, | 84 | .sd => .{ .opcode = 0b0100011, .funct3 = 0b011, .funct7 = null }, |
| 83 | .sw => .{ .opcode = 0b0100011, .funct3 = 0b010, .funct7 = null }, | 85 | .sw => .{ .opcode = 0b0100011, .funct3 = 0b010, .funct7 = null }, |
| ... | @@ -133,6 +135,7 @@ pub const InstEnc = enum { | ... | @@ -133,6 +135,7 @@ pub const InstEnc = enum { |
| 133 | => .I, | 135 | => .I, |
| 134 | 136 | ||
| 135 | .lui, | 137 | .lui, |
| 138 | .auipc, | ||
| 136 | => .U, | 139 | => .U, |
| 137 | 140 | ||
| 138 | .sd, | 141 | .sd, |
src/arch/riscv64/Lower.zig+23-1| ... | @@ -32,8 +32,10 @@ pub const Reloc = struct { | ... | @@ -32,8 +32,10 @@ pub const Reloc = struct { |
| 32 | const Target = union(enum) { | 32 | const Target = union(enum) { |
| 33 | inst: Mir.Inst.Index, | 33 | inst: Mir.Inst.Index, |
| 34 | 34 | ||
| 35 | /// Relocs the lowered_inst_index and the next one. | 35 | /// Relocs the lowered_inst_index and the next instruction. |
| 36 | load_symbol_reloc: bits.Symbol, | 36 | load_symbol_reloc: bits.Symbol, |
| 37 | /// Relocs the lowered_inst_index and the next instruction. | ||
| 38 | call_extern_fn_reloc: bits.Symbol, | ||
| 37 | }; | 39 | }; |
| 38 | }; | 40 | }; |
| 39 | 41 | ||
| ... | @@ -247,6 +249,26 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { | ... | @@ -247,6 +249,26 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { |
| 247 | }); | 249 | }); |
| 248 | }, | 250 | }, |
| 249 | 251 | ||
| 252 | .pseudo_extern_fn_reloc => { | ||
| 253 | const inst_reloc = inst.data.reloc; | ||
| 254 | |||
| 255 | try lower.emit(.auipc, &.{ | ||
| 256 | .{ .reg = .ra }, | ||
| 257 | .{ .imm = lower.reloc( | ||
| 258 | .{ .call_extern_fn_reloc = .{ | ||
| 259 | .atom_index = inst_reloc.atom_index, | ||
| 260 | .sym_index = inst_reloc.sym_index, | ||
| 261 | } }, | ||
| 262 | ) }, | ||
| 263 | }); | ||
| 264 | |||
| 265 | try lower.emit(.jalr, &.{ | ||
| 266 | .{ .reg = .ra }, | ||
| 267 | .{ .reg = .ra }, | ||
| 268 | .{ .imm = Immediate.s(0) }, | ||
| 269 | }); | ||
| 270 | }, | ||
| 271 | |||
| 250 | else => return lower.fail("TODO lower: psuedo {s}", .{@tagName(inst.ops)}), | 272 | else => return lower.fail("TODO lower: psuedo {s}", .{@tagName(inst.ops)}), |
| 251 | }, | 273 | }, |
| 252 | } | 274 | } |
src/arch/riscv64/Mir.zig+9-4| ... | @@ -202,6 +202,11 @@ pub const Inst = struct { | ... | @@ -202,6 +202,11 @@ pub const Inst = struct { |
| 202 | lte, | 202 | lte, |
| 203 | }, | 203 | }, |
| 204 | }, | 204 | }, |
| 205 | |||
| 206 | reloc: struct { | ||
| 207 | atom_index: u32, | ||
| 208 | sym_index: u32, | ||
| 209 | }, | ||
| 205 | }; | 210 | }; |
| 206 | 211 | ||
| 207 | pub const Ops = enum { | 212 | pub const Ops = enum { |
| ... | @@ -214,10 +219,7 @@ pub const Inst = struct { | ... | @@ -214,10 +219,7 @@ pub const Inst = struct { |
| 214 | 219 | ||
| 215 | /// Two registers + immediate, uses the i_type payload. | 220 | /// Two registers + immediate, uses the i_type payload. |
| 216 | rri, | 221 | rri, |
| 217 | /// Two registers + Two Immediates | 222 | //extern_fn_reloc/ Two registers + another instruction. |
| 218 | rrii, | ||
| 219 | |||
| 220 | /// Two registers + another instruction. | ||
| 221 | rr_inst, | 223 | rr_inst, |
| 222 | 224 | ||
| 223 | /// Register + Memory | 225 | /// Register + Memory |
| ... | @@ -283,6 +285,9 @@ pub const Inst = struct { | ... | @@ -283,6 +285,9 @@ pub const Inst = struct { |
| 283 | 285 | ||
| 284 | pseudo_compare, | 286 | pseudo_compare, |
| 285 | pseudo_not, | 287 | pseudo_not, |
| 288 | |||
| 289 | /// Generates an auipc + jalr pair, with a R_RISCV_CALL_PLT reloc | ||
| 290 | pseudo_extern_fn_reloc, | ||
| 286 | }; | 291 | }; |
| 287 | 292 | ||
| 288 | // Make sure we don't accidentally make instructions bigger than expected. | 293 | // Make sure we don't accidentally make instructions bigger than expected. |
src/link/Elf.zig+2-1| ... | @@ -5842,7 +5842,8 @@ pub fn tpAddress(self: *Elf) i64 { | ... | @@ -5842,7 +5842,8 @@ pub fn tpAddress(self: *Elf) i64 { |
| 5842 | const addr = switch (self.getTarget().cpu.arch) { | 5842 | const addr = switch (self.getTarget().cpu.arch) { |
| 5843 | .x86_64 => mem.alignForward(u64, phdr.p_vaddr + phdr.p_memsz, phdr.p_align), | 5843 | .x86_64 => mem.alignForward(u64, phdr.p_vaddr + phdr.p_memsz, phdr.p_align), |
| 5844 | .aarch64 => mem.alignBackward(u64, phdr.p_vaddr - 16, phdr.p_align), | 5844 | .aarch64 => mem.alignBackward(u64, phdr.p_vaddr - 16, phdr.p_align), |
| 5845 | else => @panic("TODO implement getTpAddress for this arch"), | 5845 | .riscv64 => phdr.p_vaddr, |
| 5846 | else => |arch| std.debug.panic("TODO implement getTpAddress for {s}", .{@tagName(arch)}), | ||
| 5846 | }; | 5847 | }; |
| 5847 | return @intCast(addr); | 5848 | return @intCast(addr); |
| 5848 | } | 5849 | } |
src/link/Elf/Atom.zig+46-17| ... | @@ -1409,11 +1409,11 @@ const x86_64 = struct { | ... | @@ -1409,11 +1409,11 @@ const x86_64 = struct { |
| 1409 | .GOTPC64 => try cwriter.writeInt(i64, GOT + A, .little), | 1409 | .GOTPC64 => try cwriter.writeInt(i64, GOT + A, .little), |
| 1410 | .SIZE32 => { | 1410 | .SIZE32 => { |
| 1411 | const size = @as(i64, @intCast(target.elfSym(elf_file).st_size)); | 1411 | const size = @as(i64, @intCast(target.elfSym(elf_file).st_size)); |
| 1412 | try cwriter.writeInt(u32, @as(u32, @bitCast(@as(i32, @intCast(size + A)))), .little); | 1412 | try cwriter.writeInt(u32, @bitCast(@as(i32, @intCast(size + A))), .little); |
| 1413 | }, | 1413 | }, |
| 1414 | .SIZE64 => { | 1414 | .SIZE64 => { |
| 1415 | const size = @as(i64, @intCast(target.elfSym(elf_file).st_size)); | 1415 | const size = @as(i64, @intCast(target.elfSym(elf_file).st_size)); |
| 1416 | try cwriter.writeInt(i64, @as(i64, @intCast(size + A)), .little); | 1416 | try cwriter.writeInt(i64, @intCast(size + A), .little); |
| 1417 | }, | 1417 | }, |
| 1418 | else => try atom.reportUnhandledRelocError(rel, elf_file), | 1418 | else => try atom.reportUnhandledRelocError(rel, elf_file), |
| 1419 | } | 1419 | } |
| ... | @@ -2001,26 +2001,25 @@ const riscv = struct { | ... | @@ -2001,26 +2001,25 @@ const riscv = struct { |
| 2001 | const r_type: elf.R_RISCV = @enumFromInt(rel.r_type()); | 2001 | const r_type: elf.R_RISCV = @enumFromInt(rel.r_type()); |
| 2002 | 2002 | ||
| 2003 | switch (r_type) { | 2003 | switch (r_type) { |
| 2004 | .@"64" => { | 2004 | .@"32" => try atom.scanReloc(symbol, rel, absRelocAction(symbol, elf_file), elf_file), |
| 2005 | try atom.scanReloc(symbol, rel, dynAbsRelocAction(symbol, elf_file), elf_file); | 2005 | .@"64" => try atom.scanReloc(symbol, rel, dynAbsRelocAction(symbol, elf_file), elf_file), |
| 2006 | }, | 2006 | .HI20 => try atom.scanReloc(symbol, rel, absRelocAction(symbol, elf_file), elf_file), |
| 2007 | |||
| 2008 | .HI20 => { | ||
| 2009 | try atom.scanReloc(symbol, rel, absRelocAction(symbol, elf_file), elf_file); | ||
| 2010 | }, | ||
| 2011 | 2007 | ||
| 2012 | .CALL_PLT => if (symbol.flags.import) { | 2008 | .CALL_PLT => if (symbol.flags.import) { |
| 2013 | symbol.flags.needs_plt = true; | 2009 | symbol.flags.needs_plt = true; |
| 2014 | }, | 2010 | }, |
| 2011 | .GOT_HI20 => symbol.flags.needs_got = true, | ||
| 2015 | 2012 | ||
| 2016 | .GOT_HI20 => { | 2013 | .TPREL_HI20, |
| 2017 | symbol.flags.needs_got = true; | 2014 | .TPREL_LO12_I, |
| 2018 | }, | 2015 | .TPREL_LO12_S, |
| 2016 | .TPREL_ADD, | ||
| 2019 | 2017 | ||
| 2020 | .PCREL_HI20, | 2018 | .PCREL_HI20, |
| 2021 | .PCREL_LO12_I, | 2019 | .PCREL_LO12_I, |
| 2022 | .PCREL_LO12_S, | 2020 | .PCREL_LO12_S, |
| 2023 | .LO12_I, | 2021 | .LO12_I, |
| 2022 | .LO12_S, | ||
| 2024 | .ADD32, | 2023 | .ADD32, |
| 2025 | .SUB32, | 2024 | .SUB32, |
| 2026 | => {}, | 2025 | => {}, |
| ... | @@ -2058,6 +2057,8 @@ const riscv = struct { | ... | @@ -2058,6 +2057,8 @@ const riscv = struct { |
| 2058 | switch (r_type) { | 2057 | switch (r_type) { |
| 2059 | .NONE => unreachable, | 2058 | .NONE => unreachable, |
| 2060 | 2059 | ||
| 2060 | .@"32" => try cwriter.writeInt(u32, @as(u32, @truncate(@as(u64, @intCast(S + A)))), .little), | ||
| 2061 | |||
| 2061 | .@"64" => { | 2062 | .@"64" => { |
| 2062 | try atom.resolveDynAbsReloc( | 2063 | try atom.resolveDynAbsReloc( |
| 2063 | target, | 2064 | target, |
| ... | @@ -2076,11 +2077,6 @@ const riscv = struct { | ... | @@ -2076,11 +2077,6 @@ const riscv = struct { |
| 2076 | riscv_util.writeInstU(code[r_offset..][0..4], value); | 2077 | riscv_util.writeInstU(code[r_offset..][0..4], value); |
| 2077 | }, | 2078 | }, |
| 2078 | 2079 | ||
| 2079 | .LO12_I => { | ||
| 2080 | const value: u32 = @bitCast(math.cast(i32, S + A) orelse return error.Overflow); | ||
| 2081 | riscv_util.writeInstI(code[r_offset..][0..4], value); | ||
| 2082 | }, | ||
| 2083 | |||
| 2084 | .GOT_HI20 => { | 2080 | .GOT_HI20 => { |
| 2085 | assert(target.flags.has_got); | 2081 | assert(target.flags.has_got); |
| 2086 | const disp: u32 = @bitCast(math.cast(i32, G + GOT + A - P) orelse return error.Overflow); | 2082 | const disp: u32 = @bitCast(math.cast(i32, G + GOT + A - P) orelse return error.Overflow); |
| ... | @@ -2143,6 +2139,39 @@ const riscv = struct { | ... | @@ -2143,6 +2139,39 @@ const riscv = struct { |
| 2143 | } | 2139 | } |
| 2144 | }, | 2140 | }, |
| 2145 | 2141 | ||
| 2142 | .LO12_I, | ||
| 2143 | .LO12_S, | ||
| 2144 | => { | ||
| 2145 | const disp: u32 = @bitCast(math.cast(i32, S + A) orelse return error.Overflow); | ||
| 2146 | switch (r_type) { | ||
| 2147 | .LO12_I => riscv_util.writeInstI(code[r_offset..][0..4], disp), | ||
| 2148 | .LO12_S => riscv_util.writeInstS(code[r_offset..][0..4], disp), | ||
| 2149 | else => unreachable, | ||
| 2150 | } | ||
| 2151 | }, | ||
| 2152 | |||
| 2153 | .TPREL_HI20 => { | ||
| 2154 | const target_addr: u32 = @intCast(target.address(.{}, elf_file)); | ||
| 2155 | const val: i32 = @intCast(S + A - target_addr); | ||
| 2156 | riscv_util.writeInstU(code[r_offset..][0..4], @bitCast(val)); | ||
| 2157 | }, | ||
| 2158 | |||
| 2159 | .TPREL_LO12_I, | ||
| 2160 | .TPREL_LO12_S, | ||
| 2161 | => { | ||
| 2162 | const target_addr: u32 = @intCast(target.address(.{}, elf_file)); | ||
| 2163 | const val: i32 = @intCast(S + A - target_addr); | ||
| 2164 | switch (r_type) { | ||
| 2165 | .TPREL_LO12_I => riscv_util.writeInstI(code[r_offset..][0..4], @bitCast(val)), | ||
| 2166 | .TPREL_LO12_S => riscv_util.writeInstS(code[r_offset..][0..4], @bitCast(val)), | ||
| 2167 | else => unreachable, | ||
| 2168 | } | ||
| 2169 | }, | ||
| 2170 | |||
| 2171 | .TPREL_ADD => { | ||
| 2172 | // TODO: annotates an ADD instruction that can be removed when TPREL is relaxed | ||
| 2173 | }, | ||
| 2174 | |||
| 2146 | else => |x| switch (@intFromEnum(x)) { | 2175 | else => |x| switch (@intFromEnum(x)) { |
| 2147 | // Zig custom relocations | 2176 | // Zig custom relocations |
| 2148 | Elf.R_ZIG_GOT_HI20 => { | 2177 | Elf.R_ZIG_GOT_HI20 => { |