authorgravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-04-22 20:40:55-07:00
committergravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-06-13 02:19:39-07:00
logfcafaae747c0d032401ca7936b667f5dfcf0466b
treebfbf921a30a4cf275aaabb4012429e72709687e4
parent004d0c8978d4b5e4212c06abb33d7a594930f8c5
signaturelock-open Commit is signed but in an unrecognized format.

riscv: get basic libc interop


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);
35923592
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();
35963617
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 {
2222
23 // U Type23 // U Type
24 lui,24 lui,
25 auipc,
2526
26 // S Type27 // 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 },
7980
80 .lui => .{ .opcode = 0b0110111, .funct3 = null, .funct7 = null },81 .lui => .{ .opcode = 0b0110111, .funct3 = null, .funct7 = null },
82 .auipc => .{ .opcode = 0b0010111, .funct3 = null, .funct7 = null },
8183
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,
134136
135 .lui,137 .lui,
138 .auipc,
136 => .U,139 => .U,
137140
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,
3434
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};
3941
...@@ -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 },
249251
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 };
206211
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 {
214219
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 Immediates222 //extern_fn_reloc/ Two registers + another instruction.
218 rrii,
219
220 /// Two registers + another instruction.
221 rr_inst,223 rr_inst,
222224
223 /// Register + Memory225 /// Register + Memory
...@@ -283,6 +285,9 @@ pub const Inst = struct {...@@ -283,6 +285,9 @@ pub const Inst = struct {
283285
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 };
287292
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());
20022002
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 },
20112007
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,
20152012
2016 .GOT_HI20 => {2013 .TPREL_HI20,
2017 symbol.flags.needs_got = true;2014 .TPREL_LO12_I,
2018 },2015 .TPREL_LO12_S,
2016 .TPREL_ADD,
20192017
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,
20602059
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 },
20782079
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 },
21452141
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 relocations2176 // Zig custom relocations
2148 Elf.R_ZIG_GOT_HI20 => {2177 Elf.R_ZIG_GOT_HI20 => {