diff --git a/src-self-hosted/Module.zig b/src-self-hosted/Module.zig index 1ff551ecbf..da826a6e95 100644 --- a/src-self-hosted/Module.zig +++ b/src-self-hosted/Module.zig @@ -231,6 +231,7 @@ pub const Fn = struct { dependency_failure, success: Body, }, + owner_decl: *Decl, /// This memory is temporary and points to stack memory for the duration /// of Fn analysis. @@ -883,14 +884,6 @@ fn resolveDecl( }; const arena_state = try decl_scope.arena.allocator.create(std.heap.ArenaAllocator.State); - const has_codegen_bits = typed_value.ty.hasCodeGenBits(); - if (has_codegen_bits) { - // We don't fully codegen the decl until later, but we do need to reserve a global - // offset table index for it. This allows us to codegen decls out of dependency order, - // increasing how many computations can be done in parallel. - try self.bin_file.allocateDeclIndexes(new_decl); - } - arena_state.* = decl_scope.arena.state; new_decl.typed_value = .{ @@ -900,7 +893,12 @@ fn resolveDecl( }, }; new_decl.analysis = .complete; - if (has_codegen_bits) { + if (typed_value.ty.hasCodeGenBits()) { + // We don't fully codegen the decl until later, but we do need to reserve a global + // offset table index for it. This allows us to codegen decls out of dependency order, + // increasing how many computations can be done in parallel. + try self.bin_file.allocateDeclIndexes(new_decl); + // We ensureCapacity when scanning for decls. self.work_queue.writeItemAssumeCapacity(.{ .codegen_decl = new_decl }); } @@ -1329,6 +1327,7 @@ fn analyzeInstFn(self: *Module, scope: *Scope, fn_inst: *zir.Inst.Fn) InnerError new_func.* = .{ .fn_type = fn_type, .analysis = .{ .queued = fn_inst }, + .owner_decl = scope.decl(), }; const fn_payload = try scope.arena().create(Value.Payload.Function); fn_payload.* = .{ .func = new_func }; diff --git a/src-self-hosted/codegen.zig b/src-self-hosted/codegen.zig index 08a7b29ca3..ca029cab80 100644 --- a/src-self-hosted/codegen.zig +++ b/src-self-hosted/codegen.zig @@ -203,7 +203,20 @@ const Function = struct { if (func_inst.val.cast(Value.Payload.Function)) |func_val| { const func = func_val.func; - return self.fail(inst.base.src, "TODO implement calling function", .{}); + const got = &self.bin_file.program_headers.items[self.bin_file.phdr_got_index.?]; + const ptr_bits = self.target.cpu.arch.ptrBitWidth(); + const ptr_bytes: u64 = @divExact(ptr_bits, 8); + const got_addr = @intCast(u32, got.p_vaddr + func.owner_decl.link.offset_table_index * ptr_bytes); + // ff 14 25 xx xx xx xx call [addr] + try self.code.resize(self.code.items.len + 7); + self.code.items[self.code.items.len - 7 ..][0..3].* = [3]u8{ 0xff, 0x14, 0x25 }; + mem.writeIntLittle(u32, self.code.items[self.code.items.len - 4 ..][0..4], got_addr); + const return_type = func.fn_type.fnReturnType(); + switch (return_type.zigTypeTag()) { + .Void => return MCValue{ .none = {} }, + .NoReturn => return MCValue{ .unreach = {} }, + else => return self.fail(inst.base.src, "TODO implement fn call with non-void return value", .{}), + } } else { return self.fail(inst.base.src, "TODO implement calling weird function values", .{}); } diff --git a/src-self-hosted/link.zig b/src-self-hosted/link.zig index a0c7ec8493..7dfe2ed5e1 100644 --- a/src-self-hosted/link.zig +++ b/src-self-hosted/link.zig @@ -740,6 +740,7 @@ pub const ElfFile = struct { const amt = try self.file.?.copyRangeAll(shdr.sh_offset, self.file.?, new_offset, text_size); if (amt != text_size) return error.InputOutput; shdr.sh_offset = new_offset; + phdr.p_offset = new_offset; } // Now that we know the code size, we need to update the program header for executable code shdr.sh_size = needed_size; @@ -1034,6 +1035,7 @@ pub const ElfFile = struct { const amt = try self.file.?.copyRangeAll(shdr.sh_offset, self.file.?, new_offset, shdr.sh_size); if (amt != shdr.sh_size) return error.InputOutput; shdr.sh_offset = new_offset; + phdr.p_offset = new_offset; } shdr.sh_size = needed_size; phdr.p_memsz = needed_size; diff --git a/test/stage2/zir.zig b/test/stage2/zir.zig index afee3e7895..d06f38d0ad 100644 --- a/test/stage2/zir.zig +++ b/test/stage2/zir.zig @@ -209,4 +209,57 @@ pub fn addCases(ctx: *TestContext) void { \\ }, ); + + ctx.addZIRCompareOutput( + "function call with no args no return value", + &[_][]const u8{ + \\@noreturn = primitive(noreturn) + \\@void = primitive(void) + \\@usize = primitive(usize) + \\@0 = int(0) + \\@1 = int(1) + \\@2 = int(2) + \\@3 = int(3) + \\ + \\@syscall_array = str("syscall") + \\@sysoutreg_array = str("={rax}") + \\@rax_array = str("{rax}") + \\@rdi_array = str("{rdi}") + \\@rcx_array = str("rcx") + \\@r11_array = str("r11") + \\@memory_array = str("memory") + \\ + \\@exit0_fnty = fntype([], @noreturn) + \\@exit0 = fn(@exit0_fnty, { + \\ %SYS_exit_group = int(231) + \\ %exit_code = as(@usize, @0) + \\ + \\ %syscall = ref(@syscall_array) + \\ %sysoutreg = ref(@sysoutreg_array) + \\ %rax = ref(@rax_array) + \\ %rdi = ref(@rdi_array) + \\ %rcx = ref(@rcx_array) + \\ %r11 = ref(@r11_array) + \\ %memory = ref(@memory_array) + \\ + \\ %rc = asm(%syscall, @usize, + \\ volatile=1, + \\ output=%sysoutreg, + \\ inputs=[%rax, %rdi], + \\ clobbers=[%rcx, %r11, %memory], + \\ args=[%SYS_exit_group, %exit_code]) + \\ + \\ %99 = unreachable() + \\}); + \\ + \\@start_fnty = fntype([], @noreturn, cc=Naked) + \\@start = fn(@start_fnty, { + \\ %0 = call(@exit0, []) + \\}) + \\@9 = str("_start") + \\@10 = ref(@9) + \\@11 = export(@10, @start) + }, + &[_][]const u8{""}, + ); }