hello_world: finish producing a hello world exe

Section manager redesign
Linker relocations
Using global strings
String literal fixup in sema
This commit is contained in:
David Gonzalez Martin 2023-11-10 17:05:03 -06:00
parent 73769beb32
commit 31185e6779
7 changed files with 442 additions and 412 deletions

View File

@ -43,3 +43,5 @@ jobs:
nat/first
zig build run -- test/stack/main.nat
nat/stack
zig build run -- test/hello_world/main.nat
nat/hello_world

View File

@ -10,22 +10,13 @@ const emit = @import("emit.zig");
const page_size = 0x1000;
pub fn writeToMemory(image: *emit.Result) !std.ArrayListAlignedUnmanaged(u8, page_size) {
var file = try std.ArrayListAlignedUnmanaged(u8, 0x1000).initCapacity(image.allocator, 0x100000);
_ = try image.insertSection(0, .{
.name = "",
.size = page_size,
.alignment = page_size,
.flags = .{
.read = true,
.write = false,
.execute = false,
},
.type = .loadable_program,
});
const allocator = image.section_manager.allocator;
const symbol_table_index = try image.addSection(.{
try image.section_manager.addNullSection();
const symbol_table_index = try image.section_manager.addSection(.{
.name = ".symtab",
.size = page_size,
.size_guess = 50,
.alignment = @alignOf(SymbolTable.Entry),
.flags = .{
.read = false,
@ -34,9 +25,9 @@ pub fn writeToMemory(image: *emit.Result) !std.ArrayListAlignedUnmanaged(u8, pag
},
.type = .symbol_table,
});
const string_table_index = try image.addSection(.{
const string_table_index = try image.section_manager.addSection(.{
.name = ".strtab",
.size = page_size,
.size_guess = 50,
.alignment = 1,
.flags = .{
.read = false,
@ -45,9 +36,9 @@ pub fn writeToMemory(image: *emit.Result) !std.ArrayListAlignedUnmanaged(u8, pag
},
.type = .string_table,
});
const section_header_string_table_index = try image.addSection(.{
const section_header_string_table_index = try image.section_manager.addSection(.{
.name = ".shstrtab",
.size = page_size,
.size_guess = 50,
.alignment = 1,
.flags = .{
.read = false,
@ -62,7 +53,7 @@ pub fn writeToMemory(image: *emit.Result) !std.ArrayListAlignedUnmanaged(u8, pag
const program_header_count = blk: {
var result: usize = 0;
for (image.sections.items) |section| {
for (image.section_manager.sections.items) |section| {
result += @intFromBool(switch (section.type) {
.null => false,
.loadable_program => true,
@ -75,7 +66,7 @@ pub fn writeToMemory(image: *emit.Result) !std.ArrayListAlignedUnmanaged(u8, pag
var symbol_name_offset: u32 = 0;
image.writeToSection(symbol_table_index, std.mem.asBytes(&SymbolTable.Entry{
try image.section_manager.appendToSection(symbol_table_index, std.mem.asBytes(&SymbolTable.Entry{
.name_offset = symbol_name_offset,
.information = 0,
.other = 0,
@ -84,154 +75,172 @@ pub fn writeToMemory(image: *emit.Result) !std.ArrayListAlignedUnmanaged(u8, pag
.size = 0,
}));
image.writeToSection(string_table_index, "");
image.writeByteToSection(string_table_index, 0);
try image.section_manager.appendToSection(string_table_index, "");
try image.section_manager.appendByteToSection(string_table_index, 0);
symbol_name_offset += 1;
for (image.sections.items) |section| {
image.writeToSection(section_header_string_table_index, section.name);
image.writeByteToSection(section_header_string_table_index, 0);
for (image.section_manager.sections.items) |section| {
try image.section_manager.appendToSection(section_header_string_table_index, section.name);
try image.section_manager.appendByteToSection(section_header_string_table_index, 0);
}
{
var program_segment_offset: usize = 0;
try image.section_manager.appendToSection(0, std.mem.asBytes(&Header{
.endianness = .little,
.machine = switch (image.target.cpu.arch) {
.x86_64 => .AMD64,
else => unreachable,
},
.os_abi = switch (image.target.os.tag) {
.linux => .systemv,
else => unreachable,
},
.entry = 0, // overwritten later
.section_header_offset = 0, // overwritten later
.program_header_count = @intCast(program_header_count),
.section_header_count = @intCast(image.section_manager.sections.items.len),
.section_header_string_table_index = @intCast(section_header_string_table_index),
}));
image.writeToSection(0, std.mem.asBytes(&Header{
.endianness = .little,
.machine = switch (image.target.cpu.arch) {
.x86_64 => .AMD64,
else => unreachable,
},
.os_abi = switch (image.target.os.tag) {
.linux => .systemv,
else => unreachable,
},
.entry = 0,
.section_header_offset = 0,
.program_header_count = @intCast(program_header_count),
.section_header_count = @intCast(image.sections.items.len),
.section_header_string_table_index = @intCast(section_header_string_table_index),
}));
var program_segment_offset: usize = 0;
for (image.sections.items, 0..) |section, section_index| {
switch (section.type) {
.loadable_program => {
program_segment_offset = std.mem.alignForward(usize, program_segment_offset, section.alignment);
const virtual_address = base_virtual_address + program_segment_offset;
const program_segment_size = switch (section_index) {
0 => @sizeOf(Header) + @sizeOf(ProgramHeader) * program_header_count,
else => section.index,
};
image.writeToSection(0, std.mem.asBytes(&ProgramHeader{
.type = .load,
.flags = ProgramHeader.Flags{
.executable = section.flags.execute,
.writable = section.flags.write,
.readable = section.flags.read,
},
.offset = program_segment_offset,
.virtual_address = virtual_address,
.physical_address = virtual_address,
.size_in_file = program_segment_size,
.size_in_memory = program_segment_size,
.alignment = section.alignment,
}));
for (image.section_manager.sections.items, 0..) |section, section_index| {
switch (section.type) {
.loadable_program => {
program_segment_offset = std.mem.alignForward(usize, program_segment_offset, section.alignment);
const virtual_address = base_virtual_address + program_segment_offset;
const program_segment_size = switch (section_index) {
0 => @sizeOf(Header) + @sizeOf(ProgramHeader) * program_header_count,
else => section.bytes.items.len,
};
program_segment_offset += program_segment_size;
},
.null,
.string_table,
.symbol_table,
=> {},
}
}
}
{
var section_offset: usize = 0;
var section_headers = try ArrayList(SectionHeader).initCapacity(image.allocator, image.sections.items.len);
var section_name_offset: u32 = 0;
for (image.sections.items, 0..) |section, section_i| {
section_offset = std.mem.alignForward(usize, section_offset, section.alignment);
const virtual_address = base_virtual_address + section_offset;
for (section.symbol_table.keys(), section.symbol_table.values()) |symbol_name, symbol_offset| {
const symbol_address = virtual_address + symbol_offset;
image.writeToSection(symbol_table_index, std.mem.asBytes(&SymbolTable.Entry{
.name_offset = symbol_name_offset,
.information = 0x10,
.other = 0,
.section_header_index = @intCast(section_i),
.value = symbol_address,
.size = 0,
try image.section_manager.appendToSection(0, std.mem.asBytes(&ProgramHeader{
.type = .load,
.flags = ProgramHeader.Flags{
.executable = section.flags.execute,
.writable = section.flags.write,
.readable = section.flags.read,
},
.offset = program_segment_offset,
.virtual_address = virtual_address,
.physical_address = virtual_address,
.size_in_file = program_segment_size,
.size_in_memory = program_segment_size,
.alignment = section.alignment,
}));
image.writeToSection(string_table_index, symbol_name);
image.writeByteToSection(string_table_index, 0);
program_segment_offset += program_segment_size;
},
.null,
.string_table,
.symbol_table,
=> {},
}
}
symbol_name_offset += @intCast(symbol_name.len + 1);
}
var file = try std.ArrayListAlignedUnmanaged(u8, 0x1000).initCapacity(allocator, 0x100000);
var section_headers = try ArrayList(SectionHeader).initCapacity(allocator, image.section_manager.sections.items.len);
var section_name_offset: u32 = 0;
const source = section.content[0..section.index];
file.items.len = section_offset + source.len;
try file.replaceRange(image.allocator, section_offset, source.len, source);
for (image.section_manager.sections.items, 0..) |section, section_i| {
const section_offset = std.mem.alignForward(usize, file.items.len, section.alignment);
const virtual_address = base_virtual_address + section_offset;
section_headers.appendAssumeCapacity(SectionHeader{
.name_offset = section_name_offset,
.type = switch (section_i) {
0 => .null,
else => switch (section.type) {
.loadable_program => .program_data,
.string_table => .string_table,
.symbol_table => .symbol_table,
.null => .null,
},
},
.flags = .{
.alloc = true,
.executable = section.flags.execute,
.writable = section.flags.write,
},
.virtual_address = virtual_address,
.file_offset = section_offset,
.size = section.index,
.link = switch (section.type) {
.symbol_table => @intCast(string_table_index),
else => 0,
},
.info = switch (section.type) {
.symbol_table => 1,
else => 0,
},
.alignment = 0,
.entry_size = switch (section.type) {
.symbol_table => @sizeOf(SymbolTable.Entry),
else => 0,
},
});
section_offset += section.index;
section_name_offset += @intCast(section.name.len + 1);
if (file.items.len < section_offset) {
try file.appendNTimes(allocator, 0, section_offset - file.items.len);
}
const section_header_offset = std.mem.alignForward(usize, section_offset, @alignOf(SectionHeader));
const section_header_bytes = std.mem.sliceAsBytes(section_headers.items);
try file.ensureTotalCapacity(image.allocator, section_header_offset + section_header_bytes.len);
file.items.len = section_header_offset + section_header_bytes.len;
try file.replaceRange(image.allocator, section_header_offset, section_header_bytes.len, section_header_bytes);
for (section.symbol_table.keys(), section.symbol_table.values()) |symbol_name, symbol_offset| {
const symbol_address = virtual_address + symbol_offset;
try image.section_manager.appendToSection(symbol_table_index, std.mem.asBytes(&SymbolTable.Entry{
.name_offset = symbol_name_offset,
.information = 0x10,
.other = 0,
.section_header_index = @intCast(section_i),
.value = symbol_address,
.size = 0,
}));
const _start_offset = blk: {
const entry_offset = image.sections.items[text_section_index].symbol_table.values()[image.entry_point];
const text_section_virtual_address = section_headers.items[text_section_index].virtual_address;
break :blk text_section_virtual_address + entry_offset;
};
try image.section_manager.appendToSection(string_table_index, symbol_name);
try image.section_manager.appendByteToSection(string_table_index, 0);
const header: *Header = @ptrCast(file.items.ptr);
header.section_header_offset = section_header_offset;
header.entry = _start_offset;
symbol_name_offset += @intCast(symbol_name.len + 1);
}
try file.appendSlice(image.section_manager.allocator, section.bytes.items);
section_headers.appendAssumeCapacity(SectionHeader{
.name_offset = section_name_offset,
.type = switch (section_i) {
0 => .null,
else => switch (section.type) {
.loadable_program => .program_data,
.string_table => .string_table,
.symbol_table => .symbol_table,
.null => .null,
},
},
.flags = .{
.alloc = true,
.executable = section.flags.execute,
.writable = section.flags.write,
},
.virtual_address = virtual_address,
.file_offset = section_offset,
.size = section.bytes.items.len,
.link = switch (section.type) {
.symbol_table => @intCast(string_table_index),
else => 0,
},
.info = switch (section.type) {
.symbol_table => 1,
else => 0,
},
.alignment = 0,
.entry_size = switch (section.type) {
.symbol_table => @sizeOf(SymbolTable.Entry),
else => 0,
},
});
section_name_offset += @intCast(section.name.len + 1);
}
const section_header_offset = std.mem.alignForward(usize, file.items.len, @alignOf(SectionHeader));
const section_header_bytes = std.mem.sliceAsBytes(section_headers.items);
try file.ensureTotalCapacity(allocator, section_header_offset + section_header_bytes.len);
if (file.items.len < section_header_offset) {
file.appendNTimesAssumeCapacity(0, section_header_offset - file.items.len);
}
file.appendSliceAssumeCapacity(section_header_bytes);
// At this point, the file array list is not going to grow, so it's safe to practice relocations
for (image.section_manager.linker_relocations.items) |relocation| {
const source_section_index = relocation.source.index + @intFromBool(image.section_manager.null);
const target_section_index = relocation.target.index + @intFromBool(image.section_manager.null);
const source_section_header = &section_headers.items[source_section_index];
const target_section_header = &section_headers.items[target_section_index];
const source_file_offset = source_section_header.file_offset + relocation.source.offset;
const source_virtual_address = source_section_header.virtual_address + relocation.source.offset;
const target_virtual_address = target_section_header.virtual_address + relocation.target.offset;
const displacement: i32 = @intCast(@as(i64, @intCast(target_virtual_address)) - @as(i64, @intCast(source_virtual_address)));
const address_file_offset: usize = @intCast(@as(i64, @intCast(source_file_offset)) + relocation.offset);
const address_file_pointer: *align(1) i32 = @ptrCast(&file.items[address_file_offset]);
address_file_pointer.* = displacement;
}
const _start_offset = blk: {
const entry_offset = image.section_manager.sections.items[text_section_index].symbol_table.values()[image.entry_point];
const text_section_virtual_address = section_headers.items[text_section_index].virtual_address;
break :blk text_section_virtual_address + entry_offset;
};
const header: *Header = @ptrCast(file.items.ptr);
header.section_header_offset = section_header_offset;
header.entry = _start_offset;
return file;
}

View File

@ -12,6 +12,7 @@ const ir = @import("intermediate_representation.zig");
const data_structures = @import("../data_structures.zig");
const ArrayList = data_structures.ArrayList;
const ArrayListAligned = data_structures.ArrayListAligned;
const AutoHashMap = data_structures.AutoHashMap;
const mmap = data_structures.mmap;
@ -22,13 +23,12 @@ const macho = @import("macho.zig");
const jit_callconv = .SysV;
const Section = struct {
content: []align(page_size) u8,
index: usize = 0,
alignment: u32,
name: []const u8,
flags: Flags,
type: Type,
bytes: ArrayListAligned(u8, page_size),
symbol_table: std.StringArrayHashMapUnmanaged(u32) = .{},
name: []const u8,
alignment: u32,
flags: Section.Flags,
type: Section.Type,
const Type = enum {
null,
@ -44,112 +44,121 @@ const Section = struct {
};
};
pub const Result = struct {
const SectionCreation = struct {
name: []const u8,
size_guess: usize,
alignment: u32,
flags: Section.Flags,
type: Section.Type,
};
const Relocation = struct {
source: struct {
offset: u32,
index: u16,
},
target: struct {
offset: u32,
index: u16,
},
offset: i8,
};
pub const SectionManager = struct {
sections: ArrayList(Section) = .{},
// sections: struct {
// text: Section,
// rodata: Section,
// data: Section,
// },
entry_point: u32,
target: std.Target,
rodata: ?u16 = null,
null: bool = false,
linker_relocations: ArrayList(Relocation) = .{},
allocator: Allocator,
const text_section_index = 0;
pub fn addSection(section_manager: *SectionManager, arguments: SectionCreation) !usize {
const index = section_manager.sections.items.len;
pub fn create(allocator: Allocator, target: std.Target, entry_point_index: u32) !Result {
var result = Result{
// .sections = .{
// .text = .{ .content = try mmap(page_size, .{ .executable = true }) },
// .rodata = .{ .content = try mmap(page_size, .{ .executable = false }) },
// .data = .{ .content = try mmap(page_size, .{ .executable = false }) },
// },
.target = target,
.allocator = allocator,
.entry_point = entry_point_index,
};
const r = try section_manager.insertSection(index, arguments);
assert(index == r);
_ = try result.addSection(.{
.name = ".text",
.size = 0x1000,
.alignment = 0x1000,
return index;
}
pub fn getTextSectionIndex(section_manager: *const SectionManager) u16 {
return @intCast(@intFromBool(section_manager.null));
}
pub fn getTextSection(section_manager: *SectionManager) *Section {
return &section_manager.sections.items[section_manager.getTextSectionIndex()];
}
pub fn insertSection(section_manager: *SectionManager, index: usize, arguments: SectionCreation) !usize {
try section_manager.sections.insert(section_manager.allocator, index, .{
.bytes = try ArrayListAligned(u8, page_size).initCapacity(section_manager.allocator, arguments.size_guess),
.alignment = arguments.alignment,
.name = arguments.name,
.flags = arguments.flags,
.type = arguments.type,
});
return index;
}
pub fn addNullSection(section_manager: *SectionManager) !void {
const index = try section_manager.insertSection(0, .{
.name = "",
.size_guess = page_size,
.alignment = page_size,
.flags = .{
.execute = true,
.read = true,
.write = false,
.execute = false,
},
.type = .loadable_program,
});
assert(index == 0);
section_manager.null = true;
}
pub fn appendByteToSection(section_manager: *SectionManager, section_index: usize, byte: u8) !void {
try section_manager.sections.items[section_index].bytes.append(section_manager.allocator, byte);
}
pub fn appendToSection(section_manager: *SectionManager, section_index: usize, bytes: []const u8) !void {
try section_manager.sections.items[section_index].bytes.appendSlice(section_manager.allocator, bytes);
}
pub fn getSectionOffset(section_manager: *SectionManager, section_index: usize) usize {
return section_manager.sections.items[section_index].bytes.items.len;
}
pub fn getCodeOffset(section_manager: *SectionManager) usize {
return section_manager.getSectionOffset(text_section_index);
}
pub fn appendCode(section_manager: *SectionManager, code: []const u8) !void {
try section_manager.appendToSection(text_section_index, code);
}
pub fn appendCodeByte(section_manager: *SectionManager, code_byte: u8) !void {
try section_manager.appendByteToSection(text_section_index, code_byte);
}
const text_section_index = 0;
};
pub const Result = struct {
section_manager: SectionManager,
entry_point: u32,
target: std.Target,
pub fn create(section_manager: SectionManager, target: std.Target, entry_point_index: u32) !Result {
var result = Result{
.section_manager = section_manager,
.target = target,
.entry_point = entry_point_index,
};
return result;
}
const SectionCreation = struct {
name: []const u8,
size: usize,
alignment: u32,
flags: Section.Flags,
type: Section.Type,
};
pub fn addSection(result: *Result, arguments: SectionCreation) !usize {
const index = result.sections.items.len;
assert(std.mem.isAligned(arguments.size, page_size));
try result.sections.append(result.allocator, .{
.content = try mmap(arguments.size, .{ .executable = arguments.flags.execute }),
.alignment = arguments.alignment,
.name = arguments.name,
.flags = arguments.flags,
.type = arguments.type,
});
return index;
}
pub fn insertSection(result: *Result, index: usize, arguments: SectionCreation) !usize {
assert(std.mem.isAligned(arguments.size, page_size));
try result.sections.insert(result.allocator, index, .{
.content = try mmap(arguments.size, .{ .executable = arguments.flags.execute }),
.alignment = arguments.alignment,
.name = arguments.name,
.flags = arguments.flags,
.type = arguments.type,
});
return index;
}
pub fn alignSection(result: *Result, index: usize, alignment: usize) void {
const index_ptr = &result.sections.items[index].index;
index_ptr.* = std.mem.alignForward(usize, index_ptr.*, alignment);
}
pub fn writeToSection(image: *Result, section_index: usize, bytes: []const u8) void {
const section = &image.sections.items[section_index];
const destination = section.content[section.index..][0..bytes.len];
@memcpy(destination, bytes);
section.index += bytes.len;
}
pub fn writeByteToSection(image: *Result, section_index: usize, byte: u8) void {
const section = &image.sections.items[section_index];
section.content[section.index] = byte;
section.index += 1;
}
pub fn getTextSection(result: *Result) *Section {
return &result.sections.items[0];
}
pub fn appendCode(image: *Result, code: []const u8) void {
image.writeToSection(text_section_index, code);
}
pub fn appendCodeByte(image: *Result, code_byte: u8) void {
image.writeByteToSection(text_section_index, code_byte);
}
fn getEntryPoint(image: *const Result, comptime FunctionType: type) *const FunctionType {
if (@import("builtin").cpu.arch == .aarch64 and @import("builtin").os.tag == .macos) {
data_structures.pthread_jit_write_protect_np(true);

View File

@ -15,6 +15,9 @@ const AutoArrayHashMap = data_structures.AutoArrayHashMap;
const AutoHashMap = data_structures.AutoHashMap;
const StringKeyMap = data_structures.StringKeyMap;
const emit = @import("emit.zig");
const SectionManager = emit.SectionManager;
pub const Logger = enum {
function,
phi_removal,
@ -40,9 +43,9 @@ pub const Result = struct {
stack_references: BlockList(StackReference) = .{},
string_literals: BlockList(StringLiteral) = .{},
casts: BlockList(Cast) = .{},
readonly_data: ArrayList(u8) = .{},
module: *Module,
entry_point: Function.Index = Function.Index.invalid,
section_manager: emit.SectionManager,
pub fn getFunctionName(ir: *Result, function_index: Function.Declaration.Index) []const u8 {
return ir.module.getName(ir.module.function_name_map.get(@bitCast(function_index)).?).?;
@ -54,10 +57,26 @@ pub fn initialize(compilation: *Compilation, module: *Module) !*Result {
const builder = try compilation.base_allocator.create(Builder);
builder.* = .{
.allocator = compilation.base_allocator,
.module = module,
.ir = .{
.module = module,
.section_manager = SectionManager{
.allocator = compilation.base_allocator,
},
},
};
builder.ir.module = module;
_ = try builder.ir.section_manager.addSection(.{
.name = ".text",
.size_guess = 0,
.alignment = 0x1000,
.flags = .{
.execute = true,
.read = true,
.write = false,
},
.type = .loadable_program,
});
var sema_function_index = function_iterator.getCurrentIndex();
while (function_iterator.next()) |sema_function| {
@ -260,7 +279,6 @@ pub const Instruction = union(enum) {
pub const StringLiteral = struct {
offset: u32,
hash: u32,
pub const List = BlockList(@This());
pub const Index = List.Index;
@ -395,10 +413,7 @@ pub const Function = struct {
pub const Builder = struct {
allocator: Allocator,
ir: Result = .{
.module = undefined,
},
module: *Module,
ir: Result,
current_function_index: Function.Index = Function.Index.invalid,
fn currentFunction(builder: *Builder) *Function {
@ -406,7 +421,7 @@ pub const Builder = struct {
}
fn buildFunction(builder: *Builder, sema_function: Compilation.Function) !Function.Index {
const sema_prototype = builder.module.function_prototypes.get(builder.module.types.get(sema_function.prototype).function);
const sema_prototype = builder.ir.module.function_prototypes.get(builder.ir.module.types.get(sema_function.prototype).function);
const function_declaration_allocation = try builder.ir.function_declarations.addOne(builder.allocator);
const function_declaration = function_declaration_allocation.ptr;
function_declaration.* = .{
@ -420,7 +435,7 @@ pub const Builder = struct {
if (sema_prototype.arguments) |sema_arguments| {
try function_declaration.arguments.ensureTotalCapacity(builder.allocator, @intCast(sema_arguments.len));
for (sema_arguments) |sema_argument_declaration_index| {
const sema_argument_declaration = builder.module.declarations.get(sema_argument_declaration_index);
const sema_argument_declaration = builder.ir.module.declarations.get(sema_argument_declaration_index);
const argument_allocation = try builder.ir.arguments.append(builder.allocator, .{
.type = try builder.translateType(sema_argument_declaration.type),
});
@ -445,7 +460,7 @@ pub const Builder = struct {
// TODO: arguments
function.current_basic_block = try builder.newBlock();
const return_type = builder.module.types.get(sema_prototype.return_type);
const return_type = builder.ir.module.types.get(sema_prototype.return_type);
const is_noreturn = return_type.* == .noreturn;
if (!is_noreturn) {
@ -486,7 +501,7 @@ pub const Builder = struct {
});
}
const sema_block = sema_function.getBodyBlock(builder.module);
const sema_block = sema_function.getBodyBlock(builder.ir.module);
try builder.block(sema_block, .{ .emit_exit_block = !is_noreturn });
if (!is_noreturn and sema_block.reaches_end) {
@ -797,7 +812,7 @@ pub const Builder = struct {
};
fn emitSyscallArgument(builder: *Builder, sema_syscall_argument_value_index: Compilation.Value.Index) !Instruction.Index {
const sema_syscall_argument_value = builder.module.values.get(sema_syscall_argument_value_index);
const sema_syscall_argument_value = builder.ir.module.values.get(sema_syscall_argument_value_index);
return switch (sema_syscall_argument_value.*) {
.integer => |integer| try builder.processInteger(integer),
.sign_extend => |cast_index| try builder.processCast(cast_index, .sign_extend),
@ -807,8 +822,8 @@ pub const Builder = struct {
}
fn processCast(builder: *Builder, sema_cast_index: Compilation.Cast.Index, cast_type: CastType) !Instruction.Index {
const sema_cast = builder.module.casts.get(sema_cast_index);
const sema_source_value = builder.module.values.get(sema_cast.value);
const sema_cast = builder.ir.module.casts.get(sema_cast_index);
const sema_source_value = builder.ir.module.values.get(sema_cast.value);
const source_value = switch (sema_source_value.*) {
.declaration_reference => |declaration_reference| try builder.loadDeclarationReference(declaration_reference.value),
else => |t| @panic(@tagName(t)),
@ -827,7 +842,7 @@ pub const Builder = struct {
}
fn processDeclarationReferenceRaw(builder: *Builder, declaration_index: Compilation.Declaration.Index) !Instruction.Index {
const sema_declaration = builder.module.declarations.get(declaration_index);
const sema_declaration = builder.ir.module.declarations.get(declaration_index);
const result = switch (sema_declaration.scope_type) {
.local => builder.currentFunction().stack_map.get(declaration_index).?,
.global => unreachable,
@ -863,7 +878,7 @@ pub const Builder = struct {
}
fn processSyscall(builder: *Builder, sema_syscall_index: Compilation.Syscall.Index) anyerror!Instruction.Index {
const sema_syscall = builder.module.syscalls.get(sema_syscall_index);
const sema_syscall = builder.ir.module.syscalls.get(sema_syscall_index);
var arguments = try ArrayList(Instruction.Index).initCapacity(builder.allocator, sema_syscall.argument_count + 1);
const sema_syscall_number = sema_syscall.number;
@ -889,12 +904,12 @@ pub const Builder = struct {
fn block(builder: *Builder, sema_block: *Compilation.Block, options: BlockOptions) anyerror!void {
for (sema_block.statements.items) |sema_statement_index| {
const sema_statement = builder.module.values.get(sema_statement_index);
const sema_statement = builder.ir.module.values.get(sema_statement_index);
switch (sema_statement.*) {
.loop => |loop_index| {
const sema_loop = builder.module.loops.get(loop_index);
const sema_loop_condition = builder.module.values.get(sema_loop.condition);
const sema_loop_body = builder.module.values.get(sema_loop.body);
const sema_loop = builder.ir.module.loops.get(loop_index);
const sema_loop_condition = builder.ir.module.values.get(sema_loop.condition);
const sema_loop_body = builder.ir.module.values.get(sema_loop.body);
const condition: Compilation.Value.Index = switch (sema_loop_condition.*) {
.bool => |bool_value| switch (bool_value) {
true => Compilation.Value.Index.invalid,
@ -920,7 +935,7 @@ pub const Builder = struct {
.destination = loop_head_block,
});
const sema_body_block = builder.module.blocks.get(sema_loop_body.block);
const sema_body_block = builder.ir.module.blocks.get(sema_loop_body.block);
builder.currentFunction().current_basic_block = try builder.blockInsideBasicBlock(sema_body_block, loop_body_block);
if (!loop_prologue_block.invalid) {
builder.ir.blocks.get(loop_prologue_block).seal();
@ -950,7 +965,7 @@ pub const Builder = struct {
.@"unreachable" = {},
}),
.@"return" => |sema_ret_index| {
const sema_ret = builder.module.returns.get(sema_ret_index);
const sema_ret = builder.ir.module.returns.get(sema_ret_index);
const return_value = try builder.emitReturnValue(sema_ret.value);
const phi_instruction = builder.ir.instructions.get(builder.currentFunction().return_phi_node);
const phi = switch (phi_instruction.phi.invalid) {
@ -976,10 +991,10 @@ pub const Builder = struct {
});
},
.declaration => |sema_declaration_index| {
const sema_declaration = builder.module.declarations.get(sema_declaration_index);
const sema_declaration = builder.ir.module.declarations.get(sema_declaration_index);
//logln("Name: {s}\n", .{builder.module.getName(sema_declaration.name).?});
assert(sema_declaration.scope_type == .local);
const declaration_type = builder.module.types.get(sema_declaration.type);
const declaration_type = builder.ir.module.types.get(sema_declaration.type);
switch (declaration_type.*) {
.comptime_int => unreachable,
else => {
@ -1011,7 +1026,7 @@ pub const Builder = struct {
}
fn emitDeclarationInitValue(builder: *Builder, declaration_init_value_index: Compilation.Value.Index) !Instruction.Index {
const declaration_init_value = builder.module.values.get(declaration_init_value_index);
const declaration_init_value = builder.ir.module.values.get(declaration_init_value_index);
return switch (declaration_init_value.*) {
.call => |call_index| try builder.processCall(call_index),
.integer => |integer| try builder.processInteger(integer),
@ -1020,7 +1035,7 @@ pub const Builder = struct {
}
fn emitReturnValue(builder: *Builder, return_value_index: Compilation.Value.Index) !Instruction.Index {
const return_value = builder.module.values.get(return_value_index);
const return_value = builder.ir.module.values.get(return_value_index);
return switch (return_value.*) {
.syscall => |syscall_index| try builder.processSyscall(syscall_index),
.integer => |integer| try builder.processInteger(integer),
@ -1064,7 +1079,7 @@ pub const Builder = struct {
}
fn emitCallArgument(builder: *Builder, call_argument_value_index: Compilation.Value.Index) !Instruction.Index {
const call_argument_value = builder.module.values.get(call_argument_value_index);
const call_argument_value = builder.ir.module.values.get(call_argument_value_index);
return switch (call_argument_value.*) {
.integer => |integer| try builder.processInteger(integer),
.declaration_reference => |declaration_reference| try builder.loadDeclarationReference(declaration_reference.value),
@ -1074,12 +1089,12 @@ pub const Builder = struct {
}
fn processCall(builder: *Builder, sema_call_index: Compilation.Call.Index) anyerror!Instruction.Index {
const sema_call = builder.module.calls.get(sema_call_index);
const sema_call = builder.ir.module.calls.get(sema_call_index);
const sema_argument_list_index = sema_call.arguments;
const argument_list: []const Instruction.Index = switch (sema_argument_list_index.invalid) {
false => blk: {
var argument_list = ArrayList(Instruction.Index){};
const sema_argument_list = builder.module.argument_lists.get(sema_argument_list_index);
const sema_argument_list = builder.ir.module.argument_lists.get(sema_argument_list_index);
try argument_list.ensureTotalCapacity(builder.allocator, sema_argument_list.array.items.len);
for (sema_argument_list.array.items) |sema_argument_value_index| {
const argument_value_index = try builder.emitCallArgument(sema_argument_value_index);
@ -1091,7 +1106,7 @@ pub const Builder = struct {
};
const call_index = try builder.call(.{
.function = switch (builder.module.values.get(sema_call.value).*) {
.function = switch (builder.ir.module.values.get(sema_call.value).*) {
.function => |function_index| .{
.index = function_index.index,
.block = function_index.block,
@ -1109,16 +1124,34 @@ pub const Builder = struct {
}
fn processStringLiteral(builder: *Builder, string_literal_hash: u32) !Instruction.Index {
const string_literal = builder.module.string_literals.getValue(string_literal_hash).?;
const string_literal = builder.ir.module.string_literals.getValue(string_literal_hash).?;
const readonly_offset = builder.ir.readonly_data.items.len;
try builder.ir.readonly_data.appendSlice(builder.allocator, string_literal);
try builder.ir.readonly_data.append(builder.allocator, 0);
if (builder.ir.section_manager.rodata == null) {
const rodata_index = try builder.ir.section_manager.addSection(.{
.name = ".rodata",
.size_guess = 0,
.alignment = 0x1000,
.flags = .{
.read = true,
.write = false,
.execute = false,
},
.type = .loadable_program,
});
builder.ir.section_manager.rodata = @intCast(rodata_index);
}
const rodata_index = builder.ir.section_manager.rodata orelse unreachable;
const rodata_section_offset = builder.ir.section_manager.getSectionOffset(rodata_index);
try builder.ir.section_manager.appendToSection(rodata_index, string_literal);
try builder.ir.section_manager.appendByteToSection(rodata_index, 0);
const string_literal_allocation = try builder.ir.string_literals.append(builder.allocator, .{
.offset = @intCast(readonly_offset),
.hash = string_literal_hash,
.offset = @intCast(rodata_section_offset),
});
const result = try builder.append(.{
.load_string_literal = string_literal_allocation.index,
});
@ -1126,48 +1159,8 @@ pub const Builder = struct {
return result;
}
// fn emitValue(builder: *Builder, sema_value_index: Compilation.Value.Index) !Instruction.Index {
// const sema_value = builder.module.values.get(sema_value_index).*;
// return switch (sema_value) {
// .integer => |integer| try builder.append(.{
// .integer = integer,
// }),
// .call => |sema_call_index| try builder.processCall(sema_call_index),
// .declaration_reference => |sema_declaration_reference| blk: {
// },
// .syscall => |sema_syscall_index| try builder.processSyscall(sema_syscall_index),
// .string_literal => |string_literal_hash| blk: {
// const string_literal = builder.module.string_literals.getValue(string_literal_hash).?;
//
// const readonly_offset = builder.ir.readonly_data.items.len;
// try builder.ir.readonly_data.appendSlice(builder.allocator, string_literal);
//
// const string_literal_allocation = try builder.ir.string_literals.append(builder.allocator, .{
// .offset = @intCast(readonly_offset),
// .hash = string_literal_hash,
// });
// break :blk try builder.append(.{
// .string_literal = string_literal_allocation.index,
// });
// },
// .sign_extend => |sema_cast_index| blk: {
// const sema_sign_extend = builder.module.casts.get(sema_cast_index);
//
// const sign_extend = try builder.ir.casts.append(builder.allocator, .{
// .value = try builder.emitValue(sema_sign_extend.value),
// .type = try builder.translateType(sema_sign_extend.type),
// });
//
// break :blk try builder.append(.{
// .sign_extend = sign_extend.index,
// });
// },
// else => |t| @panic(@tagName(t)),
// };
// }
fn translateType(builder: *Builder, type_index: Compilation.Type.Index) !Type {
const sema_type = builder.module.types.get(type_index);
const sema_type = builder.ir.module.types.get(type_index);
return switch (sema_type.*) {
.integer => |integer| switch (integer.bit_count) {
8 => .i8,

View File

@ -1728,19 +1728,9 @@ pub const Operand = struct {
global_offset: i32 = 0,
};
const PCRelative = union(enum) {
function_declaration: MIR.Function.Index,
string_literal: ir.StringLiteral.Index,
imm32: i32,
imm8: i8,
fn function(ir_function_decl_index: ir.Function.Declaration.Index) Operand {
return Operand{
.i64i32imm_brtarget = PCRelative{
.function_declaration = ir_function_decl_index,
},
};
}
const PCRelative = struct {
index: u32,
section: u16,
};
const Lea64Mem = struct {
@ -1748,23 +1738,6 @@ pub const Operand = struct {
scale: u8,
scale_reg: ?Register,
displacement: PCRelative,
fn stringLiteral(ir_load_string_literal_index: ir.StringLiteral.Index) Operand {
return Operand{
.id = .lea64mem,
.u = .{
.lea64mem = .{
.gp64 = null, // rip
.scale = 1,
.scale_reg = null,
.displacement = PCRelative{
.string_literal = ir_load_string_literal_index,
},
},
},
.flags = .{},
};
}
};
const Immediate = u64;
@ -2561,7 +2534,8 @@ pub const MIR = struct {
.id = .i64i32imm_brtarget,
.u = .{
.pc_relative = .{
.function_declaration = mir.function_declaration_map.get(ir_call.function).?,
.index = @bitCast(mir.function_declaration_map.get(ir_call.function).?),
.section = @intCast(mir.ir.section_manager.getTextSectionIndex()),
},
},
.flags = .{},
@ -2624,6 +2598,7 @@ pub const MIR = struct {
}
},
.load_string_literal => |ir_load_string_literal_index| {
const ir_load_string_literal = mir.ir.string_literals.get(ir_load_string_literal_index);
const virtual_register = try instruction_selection.getRegisterForValue(mir, ir_instruction_index);
const virtual_operand = Operand{
.id = .gp64,
@ -2640,7 +2615,8 @@ pub const MIR = struct {
.scale = 1,
.scale_reg = null,
.displacement = Operand.PCRelative{
.string_literal = ir_load_string_literal_index,
.index = ir_load_string_literal.offset,
.section = mir.ir.section_manager.rodata orelse unreachable,
},
},
},
@ -3792,32 +3768,32 @@ pub const MIR = struct {
pub fn encode(mir: *MIR) !*emit.Result {
const image = try mir.allocator.create(emit.Result);
image.* = try emit.Result.create(mir.allocator, mir.target, mir.entry_point);
image.* = try emit.Result.create(mir.ir.section_manager, mir.target, mir.entry_point);
var function_iterator = mir.functions.iterator();
var function_offsets = std.AutoArrayHashMapUnmanaged(Function.Index, u32){};
try function_offsets.ensureTotalCapacity(mir.allocator, mir.functions.len);
try image.sections.items[0].symbol_table.ensureTotalCapacity(mir.allocator, mir.functions.len);
try image.section_manager.getTextSection().symbol_table.ensureTotalCapacity(mir.allocator, mir.functions.len);
while (function_iterator.nextPointer()) |function| {
const function_index = mir.functions.indexOf(function);
logln(.codegen, .encoding, "\n{s}:", .{function.name});
const function_offset: u32 = @intCast(image.getTextSection().index);
const function_offset: u32 = @intCast(image.section_manager.getCodeOffset());
function_offsets.putAssumeCapacityNoClobber(function_index, function_offset);
image.sections.items[0].symbol_table.putAssumeCapacityNoClobber(function.name, function_offset);
image.section_manager.getTextSection().symbol_table.putAssumeCapacityNoClobber(function.name, function_offset);
const stack_size = std.mem.alignForward(u32, computeStackSize(function.instruction_selection.stack_objects.items), 0x10);
if (stack_size != 0) {
image.appendCodeByte(0x55); // push rbp
image.appendCode(&.{ 0x48, 0x89, 0xe5 }); // mov rbp, rsp
try image.section_manager.appendCodeByte(0x55); // push rbp
try image.section_manager.appendCode(&.{ 0x48, 0x89, 0xe5 }); // mov rbp, rsp
// sub rsp, stack_offset
if (std.math.cast(u8, stack_size)) |stack_size_u8| {
image.appendCode(&.{ 0x48, 0x83, 0xec, stack_size_u8 });
try image.section_manager.appendCode(&.{ 0x48, 0x83, 0xec, stack_size_u8 });
} else {
unreachable;
}
@ -3828,7 +3804,7 @@ pub const MIR = struct {
for (block.instructions.items) |instruction_index| {
const instruction = mir.instructions.get(instruction_index);
const instruction_offset = image.getTextSection().index;
const instruction_offset = image.section_manager.getCodeOffset();
switch (instruction.id) {
.mov32r0 => {
@ -3838,14 +3814,14 @@ pub const MIR = struct {
const new_instruction_id = Instruction.Id.xor32rr;
const instruction_descriptor = instruction_descriptors.get(new_instruction_id);
const opcode: u8 = @intCast(instruction_descriptor.opcode);
image.appendCodeByte(opcode);
try image.section_manager.appendCodeByte(opcode);
const direct = true;
const modrm = ModRm{
.rm = @intCast(@intFromEnum(gp_register_encoding)),
.reg = @intCast(@intFromEnum(gp_register_encoding)),
.mod = @as(u2, @intFromBool(direct)) << 1 | @intFromBool(direct),
};
image.appendCodeByte(@bitCast(modrm));
try image.section_manager.appendCodeByte(@bitCast(modrm));
},
.ret => {},
.mov32mr => {
@ -3858,14 +3834,14 @@ pub const MIR = struct {
const memory = destination_operand.u.memory;
const instruction_descriptor = instruction_descriptors.get(instruction.id);
const opcode: u8 = @intCast(instruction_descriptor.opcode);
image.appendCodeByte(opcode);
try image.section_manager.appendCodeByte(opcode);
const modrm = ModRm{
.rm = @intFromEnum(Encoding.GP32.bp),
.reg = @intCast(@intFromEnum(source_gp32)),
.mod = @as(u2, @intFromBool(false)) << 1 | @intFromBool(true),
};
image.appendCodeByte(@bitCast(modrm));
try image.section_manager.appendCodeByte(@bitCast(modrm));
switch (memory.addressing_mode.base) {
.frame_index => |frame_index| {
@ -3873,7 +3849,7 @@ pub const MIR = struct {
const displacement_bytes: u3 = if (std.math.cast(i8, stack_offset)) |_| @sizeOf(i8) else if (std.math.cast(i32, stack_offset)) |_| @sizeOf(i32) else unreachable;
const stack_bytes = std.mem.asBytes(&stack_offset)[0..displacement_bytes];
image.appendCode(stack_bytes);
try image.section_manager.appendCode(stack_bytes);
},
else => |t| @panic(@tagName(t)),
}
@ -3887,7 +3863,7 @@ pub const MIR = struct {
.r = false,
.w = true,
};
image.appendCodeByte(@bitCast(rex));
try image.section_manager.appendCodeByte(@bitCast(rex));
const source_operand = mir.operands.get(instruction.operands.items[1]);
const source_gp64 = getGP64Encoding(source_operand.*);
@ -3897,14 +3873,14 @@ pub const MIR = struct {
const memory = destination_operand.u.memory;
const instruction_descriptor = instruction_descriptors.get(instruction.id);
const opcode: u8 = @intCast(instruction_descriptor.opcode);
image.appendCodeByte(opcode);
try image.section_manager.appendCodeByte(opcode);
const modrm = ModRm{
.rm = @intFromEnum(Encoding.GP64.bp),
.reg = @intCast(@intFromEnum(source_gp64)),
.mod = @as(u2, @intFromBool(false)) << 1 | @intFromBool(true),
};
image.appendCodeByte(@bitCast(modrm));
try image.section_manager.appendCodeByte(@bitCast(modrm));
switch (memory.addressing_mode.base) {
.frame_index => |frame_index| {
@ -3912,7 +3888,7 @@ pub const MIR = struct {
const displacement_bytes: u3 = if (std.math.cast(i8, stack_offset)) |_| @sizeOf(i8) else if (std.math.cast(i32, stack_offset)) |_| @sizeOf(i32) else unreachable;
const stack_bytes = std.mem.asBytes(&stack_offset)[0..displacement_bytes];
image.appendCode(stack_bytes);
try image.section_manager.appendCode(stack_bytes);
},
else => |t| @panic(@tagName(t)),
}
@ -3922,7 +3898,7 @@ pub const MIR = struct {
const instruction_descriptor = instruction_descriptors.get(instruction.id);
const opcode: u8 = @intCast(instruction_descriptor.opcode);
image.appendCodeByte(opcode);
try image.section_manager.appendCodeByte(opcode);
const destination_operand = mir.operands.get(instruction.operands.items[0]);
const destination_gp32 = getGP32Encoding(destination_operand.*);
@ -3936,7 +3912,7 @@ pub const MIR = struct {
.reg = @intCast(@intFromEnum(destination_gp32)),
.mod = @as(u2, @intFromBool(false)) << 1 | @intFromBool(true),
};
image.appendCodeByte(@bitCast(modrm));
try image.section_manager.appendCodeByte(@bitCast(modrm));
switch (source_memory.addressing_mode.base) {
.frame_index => |frame_index| {
@ -3944,7 +3920,7 @@ pub const MIR = struct {
const displacement_bytes: u3 = if (std.math.cast(i8, stack_offset)) |_| @sizeOf(i8) else if (std.math.cast(i32, stack_offset)) |_| @sizeOf(i32) else unreachable;
const stack_bytes = std.mem.asBytes(&stack_offset)[0..displacement_bytes];
image.appendCode(stack_bytes);
try image.section_manager.appendCode(stack_bytes);
},
else => |t| @panic(@tagName(t)),
}
@ -3958,11 +3934,11 @@ pub const MIR = struct {
.r = false,
.w = true,
};
image.appendCodeByte(@bitCast(rex));
try image.section_manager.appendCodeByte(@bitCast(rex));
const instruction_descriptor = instruction_descriptors.get(instruction.id);
const opcode: u8 = @intCast(instruction_descriptor.opcode);
image.appendCodeByte(opcode);
try image.section_manager.appendCodeByte(opcode);
const destination_operand = mir.operands.get(instruction.operands.items[0]);
const destination_gp64 = getGP64Encoding(destination_operand.*);
@ -3976,7 +3952,7 @@ pub const MIR = struct {
.reg = @intCast(@intFromEnum(destination_gp64)),
.mod = @as(u2, @intFromBool(false)) << 1 | @intFromBool(true),
};
image.appendCodeByte(@bitCast(modrm));
try image.section_manager.appendCodeByte(@bitCast(modrm));
switch (source_memory.addressing_mode.base) {
.frame_index => |frame_index| {
@ -3984,7 +3960,7 @@ pub const MIR = struct {
const displacement_bytes: u3 = if (std.math.cast(i8, stack_offset)) |_| @sizeOf(i8) else if (std.math.cast(i32, stack_offset)) |_| @sizeOf(i32) else unreachable;
const stack_bytes = std.mem.asBytes(&stack_offset)[0..displacement_bytes];
image.appendCode(stack_bytes);
try image.section_manager.appendCode(stack_bytes);
},
else => |t| @panic(@tagName(t)),
}
@ -3999,9 +3975,9 @@ pub const MIR = struct {
const destination_gp32 = getGP32Encoding(destination_operand.*);
const opcode = @as(u8, 0xb8) | @as(u3, @intCast(@intFromEnum(destination_gp32)));
image.appendCodeByte(opcode);
try image.section_manager.appendCodeByte(opcode);
image.appendCode(std.mem.asBytes(&source_immediate));
try image.section_manager.appendCode(std.mem.asBytes(&source_immediate));
},
.mov32ri64 => {
assert(instruction.operands.items.len == 2);
@ -4015,9 +3991,9 @@ pub const MIR = struct {
};
const opcode = @as(u8, 0xb8) | @as(u3, @intCast(@intFromEnum(destination_gp32)));
image.appendCodeByte(opcode);
try image.section_manager.appendCodeByte(opcode);
image.appendCode(std.mem.asBytes(&source_immediate));
try image.section_manager.appendCode(std.mem.asBytes(&source_immediate));
},
.movsx64rm32 => {
assert(instruction.operands.items.len == 2);
@ -4034,18 +4010,18 @@ pub const MIR = struct {
.r = false,
.w = true,
};
image.appendCodeByte(@bitCast(rex));
try image.section_manager.appendCodeByte(@bitCast(rex));
const instruction_descriptor = instruction_descriptors.get(instruction.id);
const opcode: u8 = @intCast(instruction_descriptor.opcode);
image.appendCodeByte(opcode);
try image.section_manager.appendCodeByte(opcode);
const modrm = ModRm{
.rm = @intFromEnum(Encoding.GP32.bp),
.reg = @intCast(@intFromEnum(destination_register)),
.mod = @as(u2, @intFromBool(false)) << 1 | @intFromBool(true),
};
image.appendCodeByte(@bitCast(modrm));
try image.section_manager.appendCodeByte(@bitCast(modrm));
switch (source_memory.addressing_mode.base) {
.frame_index => |frame_index| {
@ -4053,25 +4029,25 @@ pub const MIR = struct {
const displacement_bytes: u3 = if (std.math.cast(i8, stack_offset)) |_| @sizeOf(i8) else if (std.math.cast(i32, stack_offset)) |_| @sizeOf(i32) else unreachable;
const stack_bytes = std.mem.asBytes(&stack_offset)[0..displacement_bytes];
image.appendCode(stack_bytes);
try image.section_manager.appendCode(stack_bytes);
},
else => |t| @panic(@tagName(t)),
}
},
.syscall => image.appendCode(&.{ 0x0f, 0x05 }),
.ud2 => image.appendCode(&.{ 0x0f, 0x0b }),
.syscall => try image.section_manager.appendCode(&.{ 0x0f, 0x05 }),
.ud2 => try image.section_manager.appendCode(&.{ 0x0f, 0x0b }),
.call64pcrel32 => {
// TODO: emit relocation
assert(instruction.operands.items.len == 1);
const operand = mir.operands.get(instruction.operands.items[0]);
const instruction_descriptor = instruction_descriptors.get(instruction.id);
const opcode: u8 = @intCast(instruction_descriptor.opcode);
image.appendCodeByte(opcode);
try image.section_manager.appendCodeByte(opcode);
switch (operand.u) {
.pc_relative => |pc_relative| {
// TODO: fix
const callee = pc_relative.function_declaration;
const callee: Function.Index = @bitCast(pc_relative.index);
const caller = function_index;
const instruction_len = 5;
@ -4080,9 +4056,10 @@ pub const MIR = struct {
const callee_offset: i64 = @intCast(function_offsets.get(callee).?);
const caller_offset: i64 = @intCast(instruction_offset + instruction_len);
const offset: i32 = @intCast(callee_offset - caller_offset);
image.appendCode(std.mem.asBytes(&offset));
try image.section_manager.appendCode(std.mem.asBytes(&offset));
} else {
image.appendCode(&.{ 0, 0, 0, 0 });
// TODO: handle relocation
try image.section_manager.appendCode(&.{ 0, 0, 0, 0 });
unreachable;
}
},
@ -4097,7 +4074,7 @@ pub const MIR = struct {
switch (destination_operand.id) {
.gp32 => {
image.appendCodeByte(0x89);
try image.section_manager.appendCodeByte(0x89);
const destination_register = getGP32Encoding(destination_operand.*);
const source_register = getGP32Encoding(source_operand.*);
@ -4106,7 +4083,8 @@ pub const MIR = struct {
.reg = @intCast(@intFromEnum(source_register)),
.mod = @as(u2, @intFromBool(true)) << 1 | @intFromBool(true),
};
image.appendCodeByte(@bitCast(modrm));
try image.section_manager.appendCodeByte(@bitCast(modrm));
},
.gp64 => {
const rex = Rex{
@ -4115,9 +4093,9 @@ pub const MIR = struct {
.r = false,
.w = true,
};
image.appendCodeByte(@bitCast(rex));
try image.section_manager.appendCodeByte(@bitCast(rex));
image.appendCodeByte(0x89);
try image.section_manager.appendCodeByte(0x89);
const destination_register = getGP64Encoding(destination_operand.*);
const source_register = getGP64Encoding(source_operand.*);
@ -4126,7 +4104,7 @@ pub const MIR = struct {
.reg = @intCast(@intFromEnum(source_register)),
.mod = @as(u2, @intFromBool(true)) << 1 | @intFromBool(true),
};
image.appendCodeByte(@bitCast(modrm));
try image.section_manager.appendCodeByte(@bitCast(modrm));
},
else => |t| @panic(@tagName(t)),
}
@ -4139,11 +4117,11 @@ pub const MIR = struct {
.r = false,
.w = true,
};
image.appendCodeByte(@bitCast(rex));
try image.section_manager.appendCodeByte(@bitCast(rex));
const instruction_descriptor = instruction_descriptors.get(instruction.id);
const opcode: u8 = @intCast(instruction_descriptor.opcode);
image.appendCodeByte(opcode);
try image.section_manager.appendCodeByte(opcode);
const destination_operand = mir.operands.get(instruction.operands.items[0]);
const destination_register = getGP64Encoding(destination_operand.*);
@ -4153,7 +4131,7 @@ pub const MIR = struct {
.reg = @intCast(@intFromEnum(destination_register)),
.mod = @as(u2, @intFromBool(false)) << 1 | @intFromBool(false),
};
image.appendCodeByte(@bitCast(modrm));
try image.section_manager.appendCodeByte(@bitCast(modrm));
const source_operand = mir.operands.get(instruction.operands.items[1]);
switch (source_operand.u) {
@ -4162,19 +4140,30 @@ pub const MIR = struct {
assert(lea64mem.scale == 1);
assert(lea64mem.scale_reg == null);
switch (lea64mem.displacement) {
.string_literal => unreachable,
else => unreachable,
if (lea64mem.displacement.section == image.section_manager.rodata orelse unreachable) {
try image.section_manager.linker_relocations.append(mir.allocator, .{
.source = .{
.offset = @intCast(image.section_manager.getCodeOffset() + @sizeOf(i32)),
.index = image.section_manager.getTextSectionIndex(),
},
.target = .{
.offset = lea64mem.displacement.index,
.index = lea64mem.displacement.section,
},
.offset = -@sizeOf(i32),
});
try image.section_manager.appendCode(&.{ 0, 0, 0, 0 });
} else {
unreachable;
}
},
else => |t| @panic(@tagName(t)),
}
unreachable;
},
else => |t| @panic(@tagName(t)),
}
if (instruction_offset != image.getTextSection().index) {
if (instruction_offset != image.section_manager.getCodeOffset()) {
const print_tags = true;
if (print_tags) {
var offset = @tagName(instruction.id).len + 2;
@ -4184,7 +4173,8 @@ pub const MIR = struct {
log(.codegen, .encoding, " ", .{});
}
}
for (image.getTextSection().content[instruction_offset..image.getTextSection().index]) |byte| {
for (image.section_manager.getTextSection().bytes.items[instruction_offset..]) |byte| {
log(.codegen, .encoding, "0x{x:0>2} ", .{byte});
}
log(.codegen, .encoding, "\n", .{});
@ -4201,15 +4191,15 @@ pub const MIR = struct {
if (stack_size != 0) {
// add rsp, stack_offset
if (std.math.cast(u8, stack_size)) |stack_size_u8| {
image.appendCode(&.{ 0x48, 0x83, 0xc4, stack_size_u8 });
try image.section_manager.appendCode(&.{ 0x48, 0x83, 0xc4, stack_size_u8 });
} else {
unreachable;
}
image.appendCodeByte(0x5d); // pop rbp
try image.section_manager.appendCodeByte(0x5d); // pop rbp
}
image.appendCodeByte(0xc3);
try image.section_manager.appendCodeByte(0xc3);
}
}

View File

@ -4,6 +4,7 @@ const assert = std.debug.assert;
pub const Allocator = std.mem.Allocator;
pub const AutoArrayHashMap = std.AutoArrayHashMapUnmanaged;
pub const ArrayList = std.ArrayListUnmanaged;
pub const ArrayListAligned = std.ArrayListAlignedUnmanaged;
pub const AutoHashMap = std.AutoHashMapUnmanaged;
pub const HashMap = std.HashMapUnmanaged;
pub const SegmentedList = std.SegmentedList;

View File

@ -982,11 +982,37 @@ const Analyzer = struct {
fn processStringLiteral(analyzer: *Analyzer, scope_index: Scope.Index, node_index: Node.Index) !u32 {
const string_literal_node = analyzer.getScopeNode(scope_index, node_index);
assert(string_literal_node.id == .string_literal);
const string_literal = analyzer.tokenStringLiteral(scope_index, string_literal_node.token);
const original_string_literal = analyzer.tokenStringLiteral(scope_index, string_literal_node.token);
const string_literal = for (original_string_literal) |ch| {
if (ch == '\\') {
break try fixupStringLiteral(analyzer.allocator, original_string_literal);
}
} else original_string_literal;
const string_key = try analyzer.module.addStringLiteral(analyzer.allocator, string_literal);
return string_key;
}
fn fixupStringLiteral(allocator: Allocator, string_literal: []const u8) ![]const u8 {
var result = try ArrayList(u8).initCapacity(allocator, string_literal.len - 1);
var i: usize = 0;
while (i < string_literal.len) : (i += 1) {
const ch = string_literal[i];
if (ch != '\\') {
result.appendAssumeCapacity(ch);
} else {
const next_ch: u8 = switch (string_literal[i + 1]) {
'n' => '\n',
else => |next_ch| panic("Unexpected character: {c}, 0x{x}", .{ next_ch, next_ch }),
};
result.appendAssumeCapacity(next_ch);
i += 1;
}
}
return result.items;
}
fn functionPrototypeReturnType(analyzer: *Analyzer, function_prototype_index: Function.Prototype.Index) Type.Index {
const function_prototype = analyzer.module.function_prototypes.get(function_prototype_index);
return function_prototype.return_type;