Commit 5c4db4e578

Jakub Konka <kubkon@jakubkonka.com>
2024-01-20 22:31:50
x86_64: emit MachO TLV sequence
1 parent 080ad94
Changed files (3)
src
arch
link
src/arch/x86_64/Emit.zig
@@ -166,6 +166,8 @@ pub fn emitMir(emit: *Emit) Error!void {
                         .zig_got_load
                     else if (sym.flags.needs_got)
                         .got_load
+                    else if (sym.flags.tlv)
+                        .tlv
                     else
                         .signed;
                     try atom.addReloc(macho_file, .{
@@ -185,7 +187,6 @@ pub fn emitMir(emit: *Emit) Error!void {
                 .linker_got,
                 .linker_direct,
                 .linker_import,
-                .linker_tlv,
                 => |symbol| if (emit.lower.bin_file.cast(link.File.Elf)) |_| {
                     unreachable;
                 } else if (emit.lower.bin_file.cast(link.File.MachO)) |_| {
src/arch/x86_64/Lower.zig
@@ -62,7 +62,6 @@ pub const Reloc = struct {
         linker_got: bits.Symbol,
         linker_direct: bits.Symbol,
         linker_import: bits.Symbol,
-        linker_tlv: bits.Symbol,
     };
 };
 
@@ -428,7 +427,23 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
                         const macho_sym = macho_file.getSymbol(sym_index);
 
                         if (macho_sym.flags.tlv) {
-                            @panic("TODO lower TLS access on macOS");
+                            _ = lower.reloc(.{ .linker_reloc = sym });
+                            lower.result_insts[lower.result_insts_len] =
+                                try Instruction.new(.none, .mov, &[_]Operand{
+                                .{ .reg = .rdi },
+                                .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) },
+                            });
+                            lower.result_insts_len += 1;
+                            lower.result_insts[lower.result_insts_len] =
+                                try Instruction.new(.none, .call, &[_]Operand{
+                                .{ .mem = Memory.sib(.qword, .{ .base = .{ .reg = .rdi } }) },
+                            });
+                            lower.result_insts_len += 1;
+                            emit_mnemonic = .lea;
+                            break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{
+                                .base = .{ .reg = .rax },
+                                .disp = std.math.minInt(i32),
+                            }) };
                         }
 
                         _ = lower.reloc(.{ .linker_reloc = sym });
@@ -594,14 +609,13 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
         .extern_fn_reloc => &.{
             .{ .imm = lower.reloc(.{ .linker_extern_fn = inst.data.reloc }) },
         },
-        .got_reloc, .direct_reloc, .import_reloc, .tlv_reloc => ops: {
+        .got_reloc, .direct_reloc, .import_reloc => ops: {
             const reg = inst.data.rx.r1;
             const extra = lower.mir.extraData(bits.Symbol, inst.data.rx.payload).data;
             _ = lower.reloc(switch (inst.ops) {
                 .got_reloc => .{ .linker_got = extra },
                 .direct_reloc => .{ .linker_direct = extra },
                 .import_reloc => .{ .linker_import = extra },
-                .tlv_reloc => .{ .linker_tlv = extra },
                 else => unreachable,
             });
             break :ops &.{
src/link/MachO/ZigObject.zig
@@ -141,13 +141,23 @@ pub fn getAtomDataAlloc(self: ZigObject, macho_file: *MachO, atom: Atom) ![]u8 {
     const gpa = macho_file.base.comp.gpa;
     assert(atom.file == self.index);
     const sect = macho_file.sections.items(.header)[atom.out_n_sect];
-    const file_offset = sect.offset + atom.value - sect.addr;
-    const size = std.math.cast(usize, atom.size) orelse return error.Overflow;
-    const code = try gpa.alloc(u8, size);
-    errdefer gpa.free(code);
-    const amt = try macho_file.base.file.?.preadAll(code, file_offset);
-    if (amt != code.len) return error.InputOutput;
-    return code;
+
+    switch (sect.type()) {
+        macho.S_THREAD_LOCAL_REGULAR => {
+            const tlv = self.tls_variables.get(atom.atom_index).?;
+            const code = try gpa.dupe(u8, tlv.code);
+            return code;
+        },
+        else => {
+            const file_offset = sect.offset + atom.value - sect.addr;
+            const size = std.math.cast(usize, atom.size) orelse return error.Overflow;
+            const code = try gpa.alloc(u8, size);
+            errdefer gpa.free(code);
+            const amt = try macho_file.base.file.?.preadAll(code, file_offset);
+            if (amt != code.len) return error.InputOutput;
+            return code;
+        },
+    }
 }
 
 pub fn getAtomRelocs(self: *ZigObject, atom: Atom) []const Relocation {