mirror of
https://github.com/ziglang/zig.git
synced 2026-01-01 19:13:16 +00:00
riscv: get basic libc interop
This commit is contained in:
parent
004d0c8978
commit
fcafaae747
@ -3590,22 +3590,42 @@ fn genCall(
|
||||
const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func.owner_decl);
|
||||
const sym = elf_file.symbol(sym_index);
|
||||
|
||||
_ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
|
||||
const got_addr = sym.zigGotAddress(elf_file);
|
||||
try self.genSetReg(Type.usize, .ra, .{ .memory = @intCast(got_addr) });
|
||||
if (self.mod.pic) {
|
||||
return self.fail("TODO: genCall pic", .{});
|
||||
} else {
|
||||
_ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
|
||||
const got_addr = sym.zigGotAddress(elf_file);
|
||||
try self.genSetReg(Type.usize, .ra, .{ .memory = @intCast(got_addr) });
|
||||
|
||||
_ = try self.addInst(.{
|
||||
.tag = .jalr,
|
||||
.ops = .rri,
|
||||
.data = .{ .i_type = .{
|
||||
.rd = .ra,
|
||||
.rs1 = .ra,
|
||||
.imm12 = Immediate.s(0),
|
||||
} },
|
||||
});
|
||||
}
|
||||
} else unreachable; // not a valid riscv64 format
|
||||
},
|
||||
.extern_func => |extern_func| {
|
||||
const owner_decl = zcu.declPtr(extern_func.decl);
|
||||
const lib_name = extern_func.lib_name.toSlice(&zcu.intern_pool);
|
||||
const decl_name = owner_decl.name.toSlice(&zcu.intern_pool);
|
||||
const atom_index = try self.symbolIndex();
|
||||
|
||||
if (self.bin_file.cast(link.File.Elf)) |elf_file| {
|
||||
_ = try self.addInst(.{
|
||||
.tag = .jalr,
|
||||
.ops = .rri,
|
||||
.data = .{ .i_type = .{
|
||||
.rd = .ra,
|
||||
.rs1 = .ra,
|
||||
.imm12 = Immediate.s(0),
|
||||
.tag = .pseudo,
|
||||
.ops = .pseudo_extern_fn_reloc,
|
||||
.data = .{ .reloc = .{
|
||||
.atom_index = atom_index,
|
||||
.sym_index = try elf_file.getGlobalSymbol(decl_name, lib_name),
|
||||
} },
|
||||
});
|
||||
} else unreachable;
|
||||
} else unreachable; // not a valid riscv64 format
|
||||
},
|
||||
.extern_func => return self.fail("TODO: extern func calls", .{}),
|
||||
else => return self.fail("TODO implement calling bitcasted functions", .{}),
|
||||
}
|
||||
} else {
|
||||
@ -3613,6 +3633,7 @@ fn genCall(
|
||||
const addr_reg, const addr_lock = try self.allocReg();
|
||||
defer self.register_manager.unlockReg(addr_lock);
|
||||
try self.genSetReg(Type.usize, addr_reg, .{ .air_ref = callee });
|
||||
|
||||
_ = try self.addInst(.{
|
||||
.tag = .jalr,
|
||||
.ops = .rri,
|
||||
|
||||
@ -70,6 +70,19 @@ pub fn emitMir(emit: *Emit) Error!void {
|
||||
});
|
||||
} else return emit.fail("TODO: load_symbol_reloc non-ELF", .{});
|
||||
},
|
||||
.call_extern_fn_reloc => |symbol| {
|
||||
if (emit.lower.bin_file.cast(link.File.Elf)) |elf_file| {
|
||||
const atom_ptr = elf_file.symbol(symbol.atom_index).atom(elf_file).?;
|
||||
|
||||
const r_type: u32 = @intFromEnum(std.elf.R_RISCV.CALL_PLT);
|
||||
|
||||
try atom_ptr.addReloc(elf_file, .{
|
||||
.r_offset = start_offset,
|
||||
.r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | r_type,
|
||||
.r_addend = 0,
|
||||
});
|
||||
} else return emit.fail("TODO: call_extern_fn_reloc non-ELF", .{});
|
||||
},
|
||||
};
|
||||
}
|
||||
std.debug.assert(lowered_relocs.len == 0);
|
||||
|
||||
@ -22,6 +22,7 @@ pub const Mnemonic = enum {
|
||||
|
||||
// U Type
|
||||
lui,
|
||||
auipc,
|
||||
|
||||
// S Type
|
||||
sd,
|
||||
@ -78,6 +79,7 @@ pub const Mnemonic = enum {
|
||||
.srai => .{ .opcode = 0b0010011, .funct3 = 0b101, .funct7 = null, .offset = 1 << 10 },
|
||||
|
||||
.lui => .{ .opcode = 0b0110111, .funct3 = null, .funct7 = null },
|
||||
.auipc => .{ .opcode = 0b0010111, .funct3 = null, .funct7 = null },
|
||||
|
||||
.sd => .{ .opcode = 0b0100011, .funct3 = 0b011, .funct7 = null },
|
||||
.sw => .{ .opcode = 0b0100011, .funct3 = 0b010, .funct7 = null },
|
||||
@ -133,6 +135,7 @@ pub const InstEnc = enum {
|
||||
=> .I,
|
||||
|
||||
.lui,
|
||||
.auipc,
|
||||
=> .U,
|
||||
|
||||
.sd,
|
||||
|
||||
@ -32,8 +32,10 @@ pub const Reloc = struct {
|
||||
const Target = union(enum) {
|
||||
inst: Mir.Inst.Index,
|
||||
|
||||
/// Relocs the lowered_inst_index and the next one.
|
||||
/// Relocs the lowered_inst_index and the next instruction.
|
||||
load_symbol_reloc: bits.Symbol,
|
||||
/// Relocs the lowered_inst_index and the next instruction.
|
||||
call_extern_fn_reloc: bits.Symbol,
|
||||
};
|
||||
};
|
||||
|
||||
@ -247,6 +249,26 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
|
||||
});
|
||||
},
|
||||
|
||||
.pseudo_extern_fn_reloc => {
|
||||
const inst_reloc = inst.data.reloc;
|
||||
|
||||
try lower.emit(.auipc, &.{
|
||||
.{ .reg = .ra },
|
||||
.{ .imm = lower.reloc(
|
||||
.{ .call_extern_fn_reloc = .{
|
||||
.atom_index = inst_reloc.atom_index,
|
||||
.sym_index = inst_reloc.sym_index,
|
||||
} },
|
||||
) },
|
||||
});
|
||||
|
||||
try lower.emit(.jalr, &.{
|
||||
.{ .reg = .ra },
|
||||
.{ .reg = .ra },
|
||||
.{ .imm = Immediate.s(0) },
|
||||
});
|
||||
},
|
||||
|
||||
else => return lower.fail("TODO lower: psuedo {s}", .{@tagName(inst.ops)}),
|
||||
},
|
||||
}
|
||||
|
||||
@ -202,6 +202,11 @@ pub const Inst = struct {
|
||||
lte,
|
||||
},
|
||||
},
|
||||
|
||||
reloc: struct {
|
||||
atom_index: u32,
|
||||
sym_index: u32,
|
||||
},
|
||||
};
|
||||
|
||||
pub const Ops = enum {
|
||||
@ -214,10 +219,7 @@ pub const Inst = struct {
|
||||
|
||||
/// Two registers + immediate, uses the i_type payload.
|
||||
rri,
|
||||
/// Two registers + Two Immediates
|
||||
rrii,
|
||||
|
||||
/// Two registers + another instruction.
|
||||
//extern_fn_reloc/ Two registers + another instruction.
|
||||
rr_inst,
|
||||
|
||||
/// Register + Memory
|
||||
@ -283,6 +285,9 @@ pub const Inst = struct {
|
||||
|
||||
pseudo_compare,
|
||||
pseudo_not,
|
||||
|
||||
/// Generates an auipc + jalr pair, with a R_RISCV_CALL_PLT reloc
|
||||
pseudo_extern_fn_reloc,
|
||||
};
|
||||
|
||||
// Make sure we don't accidentally make instructions bigger than expected.
|
||||
|
||||
@ -5842,7 +5842,8 @@ pub fn tpAddress(self: *Elf) i64 {
|
||||
const addr = switch (self.getTarget().cpu.arch) {
|
||||
.x86_64 => mem.alignForward(u64, phdr.p_vaddr + phdr.p_memsz, phdr.p_align),
|
||||
.aarch64 => mem.alignBackward(u64, phdr.p_vaddr - 16, phdr.p_align),
|
||||
else => @panic("TODO implement getTpAddress for this arch"),
|
||||
.riscv64 => phdr.p_vaddr,
|
||||
else => |arch| std.debug.panic("TODO implement getTpAddress for {s}", .{@tagName(arch)}),
|
||||
};
|
||||
return @intCast(addr);
|
||||
}
|
||||
|
||||
@ -1409,11 +1409,11 @@ const x86_64 = struct {
|
||||
.GOTPC64 => try cwriter.writeInt(i64, GOT + A, .little),
|
||||
.SIZE32 => {
|
||||
const size = @as(i64, @intCast(target.elfSym(elf_file).st_size));
|
||||
try cwriter.writeInt(u32, @as(u32, @bitCast(@as(i32, @intCast(size + A)))), .little);
|
||||
try cwriter.writeInt(u32, @bitCast(@as(i32, @intCast(size + A))), .little);
|
||||
},
|
||||
.SIZE64 => {
|
||||
const size = @as(i64, @intCast(target.elfSym(elf_file).st_size));
|
||||
try cwriter.writeInt(i64, @as(i64, @intCast(size + A)), .little);
|
||||
try cwriter.writeInt(i64, @intCast(size + A), .little);
|
||||
},
|
||||
else => try atom.reportUnhandledRelocError(rel, elf_file),
|
||||
}
|
||||
@ -2001,26 +2001,25 @@ const riscv = struct {
|
||||
const r_type: elf.R_RISCV = @enumFromInt(rel.r_type());
|
||||
|
||||
switch (r_type) {
|
||||
.@"64" => {
|
||||
try atom.scanReloc(symbol, rel, dynAbsRelocAction(symbol, elf_file), elf_file);
|
||||
},
|
||||
|
||||
.HI20 => {
|
||||
try atom.scanReloc(symbol, rel, absRelocAction(symbol, elf_file), elf_file);
|
||||
},
|
||||
.@"32" => try atom.scanReloc(symbol, rel, absRelocAction(symbol, elf_file), elf_file),
|
||||
.@"64" => try atom.scanReloc(symbol, rel, dynAbsRelocAction(symbol, elf_file), elf_file),
|
||||
.HI20 => try atom.scanReloc(symbol, rel, absRelocAction(symbol, elf_file), elf_file),
|
||||
|
||||
.CALL_PLT => if (symbol.flags.import) {
|
||||
symbol.flags.needs_plt = true;
|
||||
},
|
||||
.GOT_HI20 => symbol.flags.needs_got = true,
|
||||
|
||||
.GOT_HI20 => {
|
||||
symbol.flags.needs_got = true;
|
||||
},
|
||||
.TPREL_HI20,
|
||||
.TPREL_LO12_I,
|
||||
.TPREL_LO12_S,
|
||||
.TPREL_ADD,
|
||||
|
||||
.PCREL_HI20,
|
||||
.PCREL_LO12_I,
|
||||
.PCREL_LO12_S,
|
||||
.LO12_I,
|
||||
.LO12_S,
|
||||
.ADD32,
|
||||
.SUB32,
|
||||
=> {},
|
||||
@ -2058,6 +2057,8 @@ const riscv = struct {
|
||||
switch (r_type) {
|
||||
.NONE => unreachable,
|
||||
|
||||
.@"32" => try cwriter.writeInt(u32, @as(u32, @truncate(@as(u64, @intCast(S + A)))), .little),
|
||||
|
||||
.@"64" => {
|
||||
try atom.resolveDynAbsReloc(
|
||||
target,
|
||||
@ -2076,11 +2077,6 @@ const riscv = struct {
|
||||
riscv_util.writeInstU(code[r_offset..][0..4], value);
|
||||
},
|
||||
|
||||
.LO12_I => {
|
||||
const value: u32 = @bitCast(math.cast(i32, S + A) orelse return error.Overflow);
|
||||
riscv_util.writeInstI(code[r_offset..][0..4], value);
|
||||
},
|
||||
|
||||
.GOT_HI20 => {
|
||||
assert(target.flags.has_got);
|
||||
const disp: u32 = @bitCast(math.cast(i32, G + GOT + A - P) orelse return error.Overflow);
|
||||
@ -2143,6 +2139,39 @@ const riscv = struct {
|
||||
}
|
||||
},
|
||||
|
||||
.LO12_I,
|
||||
.LO12_S,
|
||||
=> {
|
||||
const disp: u32 = @bitCast(math.cast(i32, S + A) orelse return error.Overflow);
|
||||
switch (r_type) {
|
||||
.LO12_I => riscv_util.writeInstI(code[r_offset..][0..4], disp),
|
||||
.LO12_S => riscv_util.writeInstS(code[r_offset..][0..4], disp),
|
||||
else => unreachable,
|
||||
}
|
||||
},
|
||||
|
||||
.TPREL_HI20 => {
|
||||
const target_addr: u32 = @intCast(target.address(.{}, elf_file));
|
||||
const val: i32 = @intCast(S + A - target_addr);
|
||||
riscv_util.writeInstU(code[r_offset..][0..4], @bitCast(val));
|
||||
},
|
||||
|
||||
.TPREL_LO12_I,
|
||||
.TPREL_LO12_S,
|
||||
=> {
|
||||
const target_addr: u32 = @intCast(target.address(.{}, elf_file));
|
||||
const val: i32 = @intCast(S + A - target_addr);
|
||||
switch (r_type) {
|
||||
.TPREL_LO12_I => riscv_util.writeInstI(code[r_offset..][0..4], @bitCast(val)),
|
||||
.TPREL_LO12_S => riscv_util.writeInstS(code[r_offset..][0..4], @bitCast(val)),
|
||||
else => unreachable,
|
||||
}
|
||||
},
|
||||
|
||||
.TPREL_ADD => {
|
||||
// TODO: annotates an ADD instruction that can be removed when TPREL is relaxed
|
||||
},
|
||||
|
||||
else => |x| switch (@intFromEnum(x)) {
|
||||
// Zig custom relocations
|
||||
Elf.R_ZIG_GOT_HI20 => {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user