Commit f8dd48bcd2

Jakub Konka <kubkon@jakubkonka.com>
2020-09-30 23:17:40
Fix after rebase and enable stage2 tests for macOS
Also, rewrites codegen section to store symbol address in a register to then later invoke `callq` on the register.
1 parent 5a71054
Changed files (3)
src
test
stage2
src/link/MachO.zig
@@ -262,11 +262,11 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
         dysymtab.iundefsym = nlocals + nglobals;
         dysymtab.nundefsym = nundefs;
     }
-    {
+    if (self.entry_addr) |addr| {
         // update LC_MAIN with entry offset
         const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
         const main_cmd = &self.load_commands.items[self.main_cmd_index.?].EntryPoint;
-        main_cmd.entryoff = self.entry_addr.? - text_segment.vmaddr;
+        main_cmd.entryoff = addr - text_segment.vmaddr;
     }
     {
         var last_cmd_offset: usize = @sizeOf(macho.mach_header_64);
@@ -709,6 +709,7 @@ fn darwinArchString(arch: std.Target.Cpu.Arch) []const u8 {
 pub fn deinit(self: *MachO) void {
     self.offset_table.deinit(self.base.allocator);
     self.string_table.deinit(self.base.allocator);
+    self.undef_symbols.deinit(self.base.allocator);
     self.global_symbols.deinit(self.base.allocator);
     self.local_symbols.deinit(self.base.allocator);
     self.sections.deinit(self.base.allocator);
@@ -813,7 +814,7 @@ pub fn updateDeclExports(
                 try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.items().len + 1);
                 module.failed_exports.putAssumeCapacityNoClobber(
                     exp,
-                    try Module.ErrorMsg.create(self.base.allocator, 0, "Unimplemented: ExportOptions.section", .{}),
+                    try Compilation.ErrorMsg.create(self.base.allocator, 0, "Unimplemented: ExportOptions.section", .{}),
                 );
                 continue;
             }
@@ -831,7 +832,7 @@ pub fn updateDeclExports(
                 try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.items().len + 1);
                 module.failed_exports.putAssumeCapacityNoClobber(
                     exp,
-                    try Module.ErrorMsg.create(self.base.allocator, 0, "Unimplemented: GlobalLinkage.LinkOnce", .{}),
+                    try Compilation.ErrorMsg.create(self.base.allocator, 0, "Unimplemented: GlobalLinkage.LinkOnce", .{}),
                 );
                 continue;
             },
@@ -1405,6 +1406,8 @@ fn writeAllUndefSymbols(self: *MachO) !void {
 }
 
 fn writeExportTrie(self: *MachO) !void {
+    if (self.entry_addr == null) return;
+
     // TODO implement mechanism for generating a prefix tree of the exported symbols
     // single branch export trie
     var buf = [_]u8{0} ** 24;
src/codegen.zig
@@ -1532,12 +1532,12 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
                             if (func_inst.val.cast(Value.Payload.Function)) |func_val| {
                                 const func = func_val.func;
                                 const got = &macho_file.sections.items[macho_file.got_section_index.?];
-                                const ptr_bytes = 8;
-                                const got_addr = @intCast(u32, got.addr + func.owner_decl.link.macho.offset_table_index.? * ptr_bytes);
-                                // ff 14 25 xx xx xx xx    call [addr]
-                                try self.code.ensureCapacity(self.code.items.len + 7);
-                                self.code.appendSliceAssumeCapacity(&[3]u8{ 0xff, 0x14, 0x25 });
-                                mem.writeIntLittle(u32, self.code.addManyAsArrayAssumeCapacity(4), got_addr);
+                                const got_addr = got.addr + func.owner_decl.link.macho.offset_table_index.? * @sizeOf(u64);
+                                // Here, we store the got address in %rax, and then call %rax
+                                // movabsq [addr], %rax
+                                try self.genSetReg(inst.base.src, .rax, .{ .memory = got_addr });
+                                // callq *%rax
+                                self.code.appendSliceAssumeCapacity(&[2]u8{ 0xff, 0xd0 });
                             } else {
                                 return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{});
                             }
test/stage2/test.zig
@@ -151,6 +151,45 @@ pub fn addCases(ctx: *TestContext) !void {
     {
         var case = ctx.exe("hello world", macosx_x64);
         case.addError("", &[_][]const u8{":1:1: error: no entry point found"});
+
+        // Incorrect return type
+        case.addError(
+            \\export fn _start() noreturn {
+            \\}
+        , &[_][]const u8{":2:1: error: expected noreturn, found void"});
+
+        // Regular old hello world
+        case.addCompareOutput(
+            \\export fn _start() noreturn {
+            \\    print();
+            \\
+            \\    exit();
+            \\}
+            \\
+            \\fn print() void {
+            \\    asm volatile ("syscall"
+            \\        :
+            \\        : [number] "{rax}" (0x2000004),
+            \\          [arg1] "{rdi}" (1),
+            \\          [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")),
+            \\          [arg3] "{rdx}" (14)
+            \\        : "memory"
+            \\    );
+            \\    return;
+            \\}
+            \\
+            \\fn exit() noreturn {
+            \\    asm volatile ("syscall"
+            \\        :
+            \\        : [number] "{rax}" (0x2000001),
+            \\          [arg1] "{rdi}" (0)
+            \\        : "memory"
+            \\    );
+            \\    unreachable;
+            \\}
+            ,
+            "Hello, World!\n",
+        );
     }
 
     {