Skip to content

Commit

Permalink
svm: PQR support
Browse files Browse the repository at this point in the history
  • Loading branch information
Rexicon226 committed Jan 21, 2025
1 parent a5a2d79 commit 77518dd
Show file tree
Hide file tree
Showing 5 changed files with 626 additions and 61 deletions.
55 changes: 39 additions & 16 deletions src/svm/elf.zig
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,24 @@ pub const Elf = struct {
shdrs: []align(1) const elf.Elf64_Shdr,
phdrs: []align(1) const elf.Elf64_Phdr,

fn parse(bytes: []const u8) Headers {
fn parse(bytes: []const u8) !Headers {
const header: elf.Elf64_Ehdr = @bitCast(bytes[0..@sizeOf(elf.Elf64_Ehdr)].*);

const shoff = header.e_shoff;
const shnum = header.e_shnum;
const shsize = shnum * @sizeOf(elf.Elf64_Shdr);
const shdrs = std.mem.bytesAsSlice(elf.Elf64_Shdr, bytes[shoff..][0..shsize]);
const shdrs = std.mem.bytesAsSlice(
elf.Elf64_Shdr,
try safeSlice(bytes, shoff, shsize),
);

const phoff = header.e_phoff;
const phnum = header.e_phnum;
const phsize = phnum * @sizeOf(elf.Elf64_Phdr);
const phdrs = std.mem.bytesAsSlice(elf.Elf64_Phdr, bytes[phoff..][0..phsize]);
const phdrs = std.mem.bytesAsSlice(
elf.Elf64_Phdr,
try safeSlice(bytes, phoff, phsize),
);

return .{
.bytes = bytes,
Expand Down Expand Up @@ -217,7 +223,7 @@ pub const Elf = struct {
loader: *BuiltinProgram,
config: Config,
) !Elf {
const headers = Headers.parse(bytes);
const headers = try Headers.parse(bytes);
const data = try Data.parse(headers);

const text_section = data.getShdrByName(headers, ".text") orelse
Expand Down Expand Up @@ -246,6 +252,7 @@ pub const Elf = struct {

_ = try self.function_registry.registerHashedLegacy(
allocator,
!sbpf_version.enableStaticSyscalls(),
"entrypoint",
entry_pc,
);
Expand Down Expand Up @@ -478,7 +485,11 @@ pub const Elf = struct {
const text_section = self.headers.shdrs[text_section_index];

// fixup PC-relative call instructions
const text_bytes: []u8 = self.bytes[text_section.sh_offset..][0..text_section.sh_size];
const text_bytes: []u8 = try safeSlice(
self.bytes,
text_section.sh_offset,
text_section.sh_size,
);
const instructions = try self.getInstructions();
for (instructions, 0..) |inst, i| {
if (inst.opcode == .call_imm and
Expand All @@ -490,13 +501,14 @@ pub const Elf = struct {
return error.RelativeJumpOutOfBounds;
const key = try self.function_registry.registerHashedLegacy(
allocator,
!version.enableStaticSyscalls(),
&.{},
@intCast(target_pc),
);
// offset into the instruction where the immediate is stored
const offset = (i *| 8) +| 4;
const slice = text_bytes[offset..][0..4];
std.mem.writeInt(u32, slice, key, .little);
std.mem.writeInt(u32, slice, @intCast(key), .little);
}
}

Expand Down Expand Up @@ -565,14 +577,14 @@ pub const Elf = struct {
// the target is a lddw instruction which takes up two instruction slots

const va_low = val: {
const imm_slice = self.bytes[imm_offset..][0..4];
break :val std.mem.readInt(u32, imm_slice, .little);
const imm_slice = try safeSlice(self.bytes, imm_offset, 4);
break :val std.mem.readInt(u32, imm_slice[0..4], .little);
};

const va_high = val: {
const imm_high_offset = r_offset +| 12;
const imm_slice = self.bytes[imm_high_offset..][0..4];
break :val std.mem.readInt(u32, imm_slice, .little);
const imm_slice = try safeSlice(self.bytes, imm_high_offset, 4);
break :val std.mem.readInt(u32, imm_slice[0..4], .little);
};

var ref_addr = (@as(u64, va_high) << 32) | va_low;
Expand All @@ -583,14 +595,24 @@ pub const Elf = struct {
}

{
const imm_slice = self.bytes[imm_offset..][0..4];
std.mem.writeInt(u32, imm_slice, @truncate(ref_addr), .little);
const imm_slice = try safeSlice(self.bytes, imm_offset, 4);
std.mem.writeInt(
u32,
imm_slice[0..4],
@truncate(ref_addr),
.little,
);
}

{
const imm_high_offset = r_offset +| 12;
const imm_slice = self.bytes[imm_high_offset..][0..4];
std.mem.writeInt(u32, imm_slice, @intCast(ref_addr >> 32), .little);
const imm_slice = try safeSlice(self.bytes, imm_high_offset, 4);
std.mem.writeInt(
u32,
imm_slice[0..4],
@intCast(ref_addr >> 32),
.little,
);
}
} else {
const address: u64 = switch (version) {
Expand Down Expand Up @@ -633,11 +655,12 @@ pub const Elf = struct {
const target_pc = (symbol.st_value -| text_section.sh_addr) / 8;
const key = try self.function_registry.registerHashedLegacy(
allocator,
!version.enableStaticSyscalls(),
symbol_name,
@intCast(target_pc),
);
const slice = try safeSlice(self.bytes, imm_offset, 4);
std.mem.writeInt(u32, slice[0..4], key, .little);
std.mem.writeInt(u32, slice[0..4], @intCast(key), .little);
} else {
const hash = sbpf.hashSymbolName(symbol_name);
if (config.reject_broken_elfs and
Expand Down Expand Up @@ -685,7 +708,7 @@ pub const Elf = struct {

fn safeSlice(base: anytype, start: usize, len: usize) error{OutOfBounds}!@TypeOf(base) {
if (start >= base.len) return error.OutOfBounds;
if (start +| len >= base.len) return error.OutOfBounds;
if (start +| len > base.len) return error.OutOfBounds;
return base[start..][0..len];
}
};
55 changes: 46 additions & 9 deletions src/svm/executable.zig
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,36 @@ pub const Executable = struct {
return Assembler.parse(allocator, source, config);
}

pub fn fromTextBytes(
allocator: std.mem.Allocator,
source: []const u8,
version: sbpf.SBPFVersion,
registry: *Registry(u64),
config: Config,
) !Executable {
const entry_pc = if (registry.lookupName("entrypoint")) |entry_pc|
entry_pc.value
else
try registry.registerHashedLegacy(
allocator,
!version.enableStaticSyscalls(),
"entrypoint",
0,
);

return .{
.instructions = std.mem.bytesAsSlice(sbpf.Instruction, source),
.bytes = source,
.version = version,
.config = config,
.function_registry = registry.*,
.entry_pc = entry_pc,
.ro_section = .{ .borrowed = .{ .offset = 0, .start = 0, .end = 0 } },
.from_elf = false,
.text_vaddr = memory.PROGRAM_START,
};
}

/// When the executable comes from the assembler, we need to guarantee that the
/// instructions are aligned to `sbpf.Instruction` rather than 1 like they would be
/// if we created the executable from the Elf file. The GPA requires allocations and
Expand Down Expand Up @@ -176,7 +206,7 @@ pub const Assembler = struct {
.dst = operands[0].register,
.src = .r0,
.off = 0,
.imm = @bitCast(@as(i32, @intCast(operands[1].integer))),
.imm = @truncate(@as(u64, @bitCast(operands[1].integer))),
} else .{
.opcode = @enumFromInt(bind.opc | sbpf.Instruction.x),
.dst = operands[0].register,
Expand Down Expand Up @@ -335,7 +365,12 @@ pub const Assembler = struct {
const entry_pc = if (function_registry.lookupName("entrypoint")) |entry|
entry.value
else pc: {
_ = try function_registry.registerHashedLegacy(allocator, "entrypoint", 0);
_ = try function_registry.registerHashedLegacy(
allocator,
!config.minimum_version.enableStaticSyscalls(),
"entrypoint",
0,
);
break :pc 0;
};

Expand Down Expand Up @@ -427,7 +462,7 @@ pub const Assembler = struct {

pub fn Registry(T: type) type {
return struct {
map: std.AutoHashMapUnmanaged(u32, Entry) = .{},
map: std.AutoHashMapUnmanaged(u64, Entry) = .{},

const Entry = struct {
name: []const u8,
Expand All @@ -439,7 +474,7 @@ pub fn Registry(T: type) type {
fn register(
self: *Self,
allocator: std.mem.Allocator,
key: u32,
key: u64,
name: []const u8,
value: T,
) !void {
Expand All @@ -458,7 +493,7 @@ pub fn Registry(T: type) type {
allocator: std.mem.Allocator,
name: []const u8,
value: T,
) !u32 {
) !u64 {
const key = sbpf.hashSymbolName(name);
try self.register(allocator, key, name, value);
return key;
Expand All @@ -467,18 +502,20 @@ pub fn Registry(T: type) type {
pub fn registerHashedLegacy(
self: *Self,
allocator: std.mem.Allocator,
hash_symbol_name: bool,
name: []const u8,
value: T,
) !u32 {
) !u64 {
const hash = if (std.mem.eql(u8, name, "entrypoint"))
sbpf.hashSymbolName(name)
else
sbpf.hashSymbolName(&std.mem.toBytes(value));
try self.register(allocator, hash, &.{}, value);
return hash;
const key: u64 = if (hash_symbol_name) hash else value;
try self.register(allocator, key, &.{}, value);
return key;
}

pub fn lookupKey(self: *const Self, key: u32) ?Entry {
pub fn lookupKey(self: *const Self, key: u64) ?Entry {
return self.map.get(key);
}

Expand Down
Loading

0 comments on commit 77518dd

Please sign in to comment.