| ... | ... | @@ -38,8 +38,8 @@ unnamed_consts: UnnamedConstTable = .{}, |
| 38 | 38 | /// Table of tracked AnonDecls. |
| 39 | 39 | anon_decls: AnonDeclTable = .{}, |
| 40 | 40 | |
| 41 | | /// TLS variables indexed by Atom.Index. |
| 42 | | tls_variables: TlsTable = .{}, |
| 41 | /// TLV initializers indexed by Atom.Index. |
| 42 | tlv_initializers: TlvInitializerTable = .{}, |
| 43 | 43 | |
| 44 | 44 | /// A table of relocations. |
| 45 | 45 | relocs: RelocationTable = .{}, |
| ... | ... | @@ -91,10 +91,10 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void { |
| 91 | 91 | } |
| 92 | 92 | self.relocs.deinit(allocator); |
| 93 | 93 | |
| 94 | | for (self.tls_variables.values()) |*tlv| { |
| 95 | | tlv.deinit(allocator); |
| 94 | for (self.tlv_initializers.values()) |*tlv_init| { |
| 95 | tlv_init.deinit(allocator); |
| 96 | 96 | } |
| 97 | | self.tls_variables.deinit(allocator); |
| 97 | self.tlv_initializers.deinit(allocator); |
| 98 | 98 | } |
| 99 | 99 | |
| 100 | 100 | fn addNlist(self: *ZigObject, allocator: Allocator) !Symbol.Index { |
| ... | ... | @@ -137,25 +137,35 @@ pub fn addAtom(self: *ZigObject, macho_file: *MachO) !Symbol.Index { |
| 137 | 137 | } |
| 138 | 138 | |
| 139 | 139 | /// Caller owns the memory. |
| 140 | | pub fn getAtomDataAlloc(self: ZigObject, macho_file: *MachO, atom: Atom) ![]u8 { |
| 141 | | const gpa = macho_file.base.comp.gpa; |
| 140 | pub fn getAtomDataAlloc( |
| 141 | self: ZigObject, |
| 142 | macho_file: *MachO, |
| 143 | allocator: Allocator, |
| 144 | atom: Atom, |
| 145 | ) ![]u8 { |
| 142 | 146 | assert(atom.file == self.index); |
| 143 | 147 | const sect = macho_file.sections.items(.header)[atom.out_n_sect]; |
| 148 | assert(!sect.isZerofill()); |
| 144 | 149 | |
| 145 | 150 | switch (sect.type()) { |
| 146 | 151 | macho.S_THREAD_LOCAL_REGULAR => { |
| 147 | | const tlv = self.tls_variables.get(atom.atom_index).?; |
| 148 | | const code = try gpa.dupe(u8, tlv.code); |
| 149 | | return code; |
| 152 | const tlv = self.tlv_initializers.get(atom.atom_index).?; |
| 153 | const data = try allocator.dupe(u8, tlv.data); |
| 154 | return data; |
| 155 | }, |
| 156 | macho.S_THREAD_LOCAL_VARIABLES => { |
| 157 | const data = try allocator.alloc(u8, atom.size); |
| 158 | @memset(data, 0); |
| 159 | return data; |
| 150 | 160 | }, |
| 151 | 161 | else => { |
| 152 | 162 | const file_offset = sect.offset + atom.value - sect.addr; |
| 153 | 163 | const size = std.math.cast(usize, atom.size) orelse return error.Overflow; |
| 154 | | const code = try gpa.alloc(u8, size); |
| 155 | | errdefer gpa.free(code); |
| 156 | | const amt = try macho_file.base.file.?.preadAll(code, file_offset); |
| 157 | | if (amt != code.len) return error.InputOutput; |
| 158 | | return code; |
| 164 | const data = try allocator.alloc(u8, size); |
| 165 | errdefer allocator.free(data); |
| 166 | const amt = try macho_file.base.file.?.preadAll(data, file_offset); |
| 167 | if (amt != data.len) return error.InputOutput; |
| 168 | return data; |
| 159 | 169 | }, |
| 160 | 170 | } |
| 161 | 171 | } |
| ... | ... | @@ -421,7 +431,7 @@ pub fn lowerAnonDecl( |
| 421 | 431 | self: *ZigObject, |
| 422 | 432 | macho_file: *MachO, |
| 423 | 433 | decl_val: InternPool.Index, |
| 424 | | explicit_alignment: InternPool.Alignment, |
| 434 | explicit_alignment: Atom.Alignment, |
| 425 | 435 | src_loc: Module.SrcLoc, |
| 426 | 436 | ) !codegen.Result { |
| 427 | 437 | const gpa = macho_file.base.comp.gpa; |
| ... | ... | @@ -732,6 +742,9 @@ fn updateDeclCode( |
| 732 | 742 | } |
| 733 | 743 | } |
| 734 | 744 | |
| 745 | /// Lowering a TLV on macOS involves two stages: |
| 746 | /// 1. first we lower the initializer into appopriate section (__thread_data or __thread_bss) |
| 747 | /// 2. next, we create a corresponding threadlocal variable descriptor in __thread_vars |
| 735 | 748 | fn updateTlv( |
| 736 | 749 | self: *ZigObject, |
| 737 | 750 | macho_file: *MachO, |
| ... | ... | @@ -740,9 +753,7 @@ fn updateTlv( |
| 740 | 753 | sect_index: u8, |
| 741 | 754 | code: []const u8, |
| 742 | 755 | ) !void { |
| 743 | | const comp = macho_file.base.comp; |
| 744 | | const gpa = comp.gpa; |
| 745 | | const mod = comp.module.?; |
| 756 | const mod = macho_file.base.comp.module.?; |
| 746 | 757 | const decl = mod.declPtr(decl_index); |
| 747 | 758 | const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); |
| 748 | 759 | |
| ... | ... | @@ -750,6 +761,32 @@ fn updateTlv( |
| 750 | 761 | |
| 751 | 762 | const required_alignment = decl.getAlignment(mod); |
| 752 | 763 | |
| 764 | // 1. Lower TLV initializer |
| 765 | const init_sym_index = try self.createTlvInitializer( |
| 766 | macho_file, |
| 767 | decl_name, |
| 768 | required_alignment, |
| 769 | sect_index, |
| 770 | code, |
| 771 | ); |
| 772 | |
| 773 | // 2. Create TLV descriptor |
| 774 | try self.createTlvDescriptor(macho_file, sym_index, init_sym_index, decl_name); |
| 775 | } |
| 776 | |
| 777 | fn createTlvInitializer( |
| 778 | self: *ZigObject, |
| 779 | macho_file: *MachO, |
| 780 | name: []const u8, |
| 781 | alignment: Atom.Alignment, |
| 782 | sect_index: u8, |
| 783 | code: []const u8, |
| 784 | ) !Symbol.Index { |
| 785 | const gpa = macho_file.base.comp.gpa; |
| 786 | const sym_name = try std.fmt.allocPrint(gpa, "{s}$tlv$init", .{name}); |
| 787 | defer gpa.free(sym_name); |
| 788 | |
| 789 | const sym_index = try self.addAtom(macho_file); |
| 753 | 790 | const sym = macho_file.getSymbol(sym_index); |
| 754 | 791 | const nlist = &self.symtab.items(.nlist)[sym.nlist_idx]; |
| 755 | 792 | const atom = sym.getAtom(macho_file).?; |
| ... | ... | @@ -758,7 +795,7 @@ fn updateTlv( |
| 758 | 795 | atom.out_n_sect = sect_index; |
| 759 | 796 | |
| 760 | 797 | sym.value = 0; |
| 761 | | sym.name = try macho_file.strings.insert(gpa, decl_name); |
| 798 | sym.name = try macho_file.strings.insert(gpa, sym_name); |
| 762 | 799 | atom.flags.alive = true; |
| 763 | 800 | atom.name = sym.name; |
| 764 | 801 | nlist.n_strx = sym.name; |
| ... | ... | @@ -767,23 +804,94 @@ fn updateTlv( |
| 767 | 804 | nlist.n_value = 0; |
| 768 | 805 | self.symtab.items(.size)[sym.nlist_idx] = code.len; |
| 769 | 806 | |
| 770 | | atom.alignment = required_alignment; |
| 807 | atom.alignment = alignment; |
| 771 | 808 | atom.size = code.len; |
| 772 | 809 | |
| 773 | 810 | const slice = macho_file.sections.slice(); |
| 774 | 811 | const header = slice.items(.header)[sect_index]; |
| 775 | 812 | const atoms = &slice.items(.atoms)[sect_index]; |
| 776 | 813 | |
| 777 | | const gop = try self.tls_variables.getOrPut(gpa, atom.atom_index); |
| 814 | const gop = try self.tlv_initializers.getOrPut(gpa, atom.atom_index); |
| 778 | 815 | assert(!gop.found_existing); // TODO incremental updates |
| 779 | 816 | gop.value_ptr.* = .{ .symbol_index = sym_index }; |
| 780 | 817 | |
| 781 | 818 | // We only store the data for the TLV if it's non-zerofill. |
| 782 | 819 | if (!header.isZerofill()) { |
| 783 | | gop.value_ptr.code = try gpa.dupe(u8, code); |
| 820 | gop.value_ptr.data = try gpa.dupe(u8, code); |
| 784 | 821 | } |
| 785 | 822 | |
| 786 | 823 | try atoms.append(gpa, atom.atom_index); |
| 824 | |
| 825 | return sym_index; |
| 826 | } |
| 827 | |
| 828 | fn createTlvDescriptor( |
| 829 | self: *ZigObject, |
| 830 | macho_file: *MachO, |
| 831 | sym_index: Symbol.Index, |
| 832 | init_sym_index: Symbol.Index, |
| 833 | name: []const u8, |
| 834 | ) !void { |
| 835 | const gpa = macho_file.base.comp.gpa; |
| 836 | |
| 837 | const sym = macho_file.getSymbol(sym_index); |
| 838 | const nlist = &self.symtab.items(.nlist)[sym.nlist_idx]; |
| 839 | const atom = sym.getAtom(macho_file).?; |
| 840 | const alignment = Atom.Alignment.fromNonzeroByteUnits(@alignOf(u64)); |
| 841 | const size: u64 = @sizeOf(u64) * 3; |
| 842 | |
| 843 | const sect_index = macho_file.getSectionByName("__DATA", "__thread_vars") orelse |
| 844 | try macho_file.addSection("__DATA", "__thread_vars", .{ |
| 845 | .flags = macho.S_THREAD_LOCAL_VARIABLES, |
| 846 | }); |
| 847 | sym.out_n_sect = sect_index; |
| 848 | atom.out_n_sect = sect_index; |
| 849 | |
| 850 | sym.value = 0; |
| 851 | sym.name = try macho_file.strings.insert(gpa, name); |
| 852 | atom.flags.alive = true; |
| 853 | atom.name = sym.name; |
| 854 | nlist.n_strx = sym.name; |
| 855 | nlist.n_sect = sect_index + 1; |
| 856 | nlist.n_type = macho.N_SECT; |
| 857 | nlist.n_value = 0; |
| 858 | self.symtab.items(.size)[sym.nlist_idx] = size; |
| 859 | |
| 860 | atom.alignment = alignment; |
| 861 | atom.size = size; |
| 862 | |
| 863 | const tlv_bootstrap_index = blk: { |
| 864 | const index = try self.getGlobalSymbol(macho_file, "_tlv_bootstrap", null); |
| 865 | break :blk self.symbols.items[index]; |
| 866 | }; |
| 867 | try atom.addReloc(macho_file, .{ |
| 868 | .tag = .@"extern", |
| 869 | .offset = 0, |
| 870 | .target = tlv_bootstrap_index, |
| 871 | .addend = 0, |
| 872 | .type = .unsigned, |
| 873 | .meta = .{ |
| 874 | .pcrel = false, |
| 875 | .has_subtractor = false, |
| 876 | .length = 3, |
| 877 | .symbolnum = 0, |
| 878 | }, |
| 879 | }); |
| 880 | try atom.addReloc(macho_file, .{ |
| 881 | .tag = .@"extern", |
| 882 | .offset = 16, |
| 883 | .target = init_sym_index, |
| 884 | .addend = 0, |
| 885 | .type = .unsigned, |
| 886 | .meta = .{ |
| 887 | .pcrel = false, |
| 888 | .has_subtractor = false, |
| 889 | .length = 3, |
| 890 | .symbolnum = 0, |
| 891 | }, |
| 892 | }); |
| 893 | |
| 894 | try macho_file.sections.items(.atoms)[sect_index].append(gpa, atom.atom_index); |
| 787 | 895 | } |
| 788 | 896 | |
| 789 | 897 | fn getDeclOutputSection( |
| ... | ... | @@ -888,7 +996,7 @@ fn lowerConst( |
| 888 | 996 | macho_file: *MachO, |
| 889 | 997 | name: []const u8, |
| 890 | 998 | tv: TypedValue, |
| 891 | | required_alignment: InternPool.Alignment, |
| 999 | required_alignment: Atom.Alignment, |
| 892 | 1000 | output_section_index: u8, |
| 893 | 1001 | src_loc: Module.SrcLoc, |
| 894 | 1002 | ) !LowerConstResult { |
| ... | ... | @@ -1040,7 +1148,7 @@ fn updateLazySymbol( |
| 1040 | 1148 | const gpa = macho_file.base.comp.gpa; |
| 1041 | 1149 | const mod = macho_file.base.comp.module.?; |
| 1042 | 1150 | |
| 1043 | | var required_alignment: InternPool.Alignment = .none; |
| 1151 | var required_alignment: Atom.Alignment = .none; |
| 1044 | 1152 | var code_buffer = std.ArrayList(u8).init(gpa); |
| 1045 | 1153 | defer code_buffer.deinit(); |
| 1046 | 1154 | |
| ... | ... | @@ -1315,12 +1423,12 @@ const LazySymbolMetadata = struct { |
| 1315 | 1423 | const_state: State = .unused, |
| 1316 | 1424 | }; |
| 1317 | 1425 | |
| 1318 | | const TlsVariable = struct { |
| 1426 | const TlvInitializer = struct { |
| 1319 | 1427 | symbol_index: Symbol.Index, |
| 1320 | | code: []const u8 = &[0]u8{}, |
| 1428 | data: []const u8 = &[0]u8{}, |
| 1321 | 1429 | |
| 1322 | | fn deinit(tlv: *TlsVariable, allocator: Allocator) void { |
| 1323 | | allocator.free(tlv.code); |
| 1430 | fn deinit(tlv_init: *TlvInitializer, allocator: Allocator) void { |
| 1431 | allocator.free(tlv_init.data); |
| 1324 | 1432 | } |
| 1325 | 1433 | }; |
| 1326 | 1434 | |
| ... | ... | @@ -1329,7 +1437,7 @@ const UnnamedConstTable = std.AutoHashMapUnmanaged(InternPool.DeclIndex, std.Arr |
| 1329 | 1437 | const AnonDeclTable = std.AutoHashMapUnmanaged(InternPool.Index, DeclMetadata); |
| 1330 | 1438 | const LazySymbolTable = std.AutoArrayHashMapUnmanaged(InternPool.OptionalDeclIndex, LazySymbolMetadata); |
| 1331 | 1439 | const RelocationTable = std.ArrayListUnmanaged(std.ArrayListUnmanaged(Relocation)); |
| 1332 | | const TlsTable = std.AutoArrayHashMapUnmanaged(Atom.Index, TlsVariable); |
| 1440 | const TlvInitializerTable = std.AutoArrayHashMapUnmanaged(Atom.Index, TlvInitializer); |
| 1333 | 1441 | |
| 1334 | 1442 | const assert = std.debug.assert; |
| 1335 | 1443 | const builtin = @import("builtin"); |