| ... | @@ -11,7 +11,9 @@ const codegen = @import("../codegen.zig"); | ... | @@ -11,7 +11,9 @@ const codegen = @import("../codegen.zig"); |
| 11 | const aarch64 = @import("../codegen/aarch64.zig"); | 11 | const aarch64 = @import("../codegen/aarch64.zig"); |
| 12 | const math = std.math; | 12 | const math = std.math; |
| 13 | const mem = std.mem; | 13 | const mem = std.mem; |
| | 14 | const meta = std.meta; |
| 14 | | 15 | |
| | 16 | const bind = @import("MachO/bind.zig"); |
| 15 | const trace = @import("../tracy.zig").trace; | 17 | const trace = @import("../tracy.zig").trace; |
| 16 | const build_options = @import("build_options"); | 18 | const build_options = @import("build_options"); |
| 17 | const Module = @import("../Module.zig"); | 19 | const Module = @import("../Module.zig"); |
| ... | @@ -26,7 +28,6 @@ const Trie = @import("MachO/Trie.zig"); | ... | @@ -26,7 +28,6 @@ const Trie = @import("MachO/Trie.zig"); |
| 26 | const CodeSignature = @import("MachO/CodeSignature.zig"); | 28 | const CodeSignature = @import("MachO/CodeSignature.zig"); |
| 27 | | 29 | |
| 28 | usingnamespace @import("MachO/commands.zig"); | 30 | usingnamespace @import("MachO/commands.zig"); |
| 29 | usingnamespace @import("MachO/imports.zig"); | | |
| 30 | | 31 | |
| 31 | pub const base_tag: File.Tag = File.Tag.macho; | 32 | pub const base_tag: File.Tag = File.Tag.macho; |
| 32 | | 33 | |
| ... | @@ -87,14 +88,12 @@ code_signature_cmd_index: ?u16 = null, | ... | @@ -87,14 +88,12 @@ code_signature_cmd_index: ?u16 = null, |
| 87 | | 88 | |
| 88 | /// Index into __TEXT,__text section. | 89 | /// Index into __TEXT,__text section. |
| 89 | text_section_index: ?u16 = null, | 90 | text_section_index: ?u16 = null, |
| 90 | /// Index into __TEXT,__ziggot section. | | |
| 91 | got_section_index: ?u16 = null, | | |
| 92 | /// Index into __TEXT,__stubs section. | 91 | /// Index into __TEXT,__stubs section. |
| 93 | stubs_section_index: ?u16 = null, | 92 | stubs_section_index: ?u16 = null, |
| 94 | /// Index into __TEXT,__stub_helper section. | 93 | /// Index into __TEXT,__stub_helper section. |
| 95 | stub_helper_section_index: ?u16 = null, | 94 | stub_helper_section_index: ?u16 = null, |
| 96 | /// Index into __DATA_CONST,__got section. | 95 | /// Index into __DATA_CONST,__got section. |
| 97 | data_got_section_index: ?u16 = null, | 96 | got_section_index: ?u16 = null, |
| 98 | /// Index into __DATA,__la_symbol_ptr section. | 97 | /// Index into __DATA,__la_symbol_ptr section. |
| 99 | la_symbol_ptr_section_index: ?u16 = null, | 98 | la_symbol_ptr_section_index: ?u16 = null, |
| 100 | /// Index into __DATA,__data section. | 99 | /// Index into __DATA,__data section. |
| ... | @@ -104,16 +103,16 @@ entry_addr: ?u64 = null, | ... | @@ -104,16 +103,16 @@ entry_addr: ?u64 = null, |
| 104 | | 103 | |
| 105 | /// Table of all local symbols | 104 | /// Table of all local symbols |
| 106 | /// Internally references string table for names (which are optional). | 105 | /// Internally references string table for names (which are optional). |
| 107 | local_symbols: std.ArrayListUnmanaged(macho.nlist_64) = .{}, | 106 | locals: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| 108 | /// Table of all global symbols | 107 | /// Table of all global symbols |
| 109 | global_symbols: std.ArrayListUnmanaged(macho.nlist_64) = .{}, | 108 | globals: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| 110 | /// Table of all extern nonlazy symbols, indexed by name. | 109 | /// Table of all extern nonlazy symbols, indexed by name. |
| 111 | extern_nonlazy_symbols: std.StringArrayHashMapUnmanaged(ExternSymbol) = .{}, | 110 | nonlazy_imports: std.StringArrayHashMapUnmanaged(Import) = .{}, |
| 112 | /// Table of all extern lazy symbols, indexed by name. | 111 | /// Table of all extern lazy symbols, indexed by name. |
| 113 | extern_lazy_symbols: std.StringArrayHashMapUnmanaged(ExternSymbol) = .{}, | 112 | lazy_imports: std.StringArrayHashMapUnmanaged(Import) = .{}, |
| 114 | | 113 | |
| 115 | local_symbol_free_list: std.ArrayListUnmanaged(u32) = .{}, | 114 | locals_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 116 | global_symbol_free_list: std.ArrayListUnmanaged(u32) = .{}, | 115 | globals_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 117 | offset_table_free_list: std.ArrayListUnmanaged(u32) = .{}, | 116 | offset_table_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 118 | | 117 | |
| 119 | stub_helper_stubs_start_off: ?u64 = null, | 118 | stub_helper_stubs_start_off: ?u64 = null, |
| ... | @@ -122,8 +121,8 @@ stub_helper_stubs_start_off: ?u64 = null, | ... | @@ -122,8 +121,8 @@ stub_helper_stubs_start_off: ?u64 = null, |
| 122 | string_table: std.ArrayListUnmanaged(u8) = .{}, | 121 | string_table: std.ArrayListUnmanaged(u8) = .{}, |
| 123 | string_table_directory: std.StringHashMapUnmanaged(u32) = .{}, | 122 | string_table_directory: std.StringHashMapUnmanaged(u32) = .{}, |
| 124 | | 123 | |
| 125 | /// Table of trampolines to the actual symbols in __text section. | 124 | /// Table of GOT entries. |
| 126 | offset_table: std.ArrayListUnmanaged(u64) = .{}, | 125 | offset_table: std.ArrayListUnmanaged(GOTEntry) = .{}, |
| 127 | | 126 | |
| 128 | error_flags: File.ErrorFlags = File.ErrorFlags{}, | 127 | error_flags: File.ErrorFlags = File.ErrorFlags{}, |
| 129 | | 128 | |
| ... | @@ -154,14 +153,19 @@ string_table_needs_relocation: bool = false, | ... | @@ -154,14 +153,19 @@ string_table_needs_relocation: bool = false, |
| 154 | /// allocate a fresh text block, which will have ideal capacity, and then grow it | 153 | /// allocate a fresh text block, which will have ideal capacity, and then grow it |
| 155 | /// by 1 byte. It will then have -1 overcapacity. | 154 | /// by 1 byte. It will then have -1 overcapacity. |
| 156 | text_block_free_list: std.ArrayListUnmanaged(*TextBlock) = .{}, | 155 | text_block_free_list: std.ArrayListUnmanaged(*TextBlock) = .{}, |
| | 156 | |
| 157 | /// Pointer to the last allocated text block | 157 | /// Pointer to the last allocated text block |
| 158 | last_text_block: ?*TextBlock = null, | 158 | last_text_block: ?*TextBlock = null, |
| | 159 | |
| 159 | /// A list of all PIE fixups required for this run of the linker. | 160 | /// A list of all PIE fixups required for this run of the linker. |
| 160 | /// Warning, this is currently NOT thread-safe. See the TODO below. | 161 | /// Warning, this is currently NOT thread-safe. See the TODO below. |
| 161 | /// TODO Move this list inside `updateDecl` where it should be allocated | 162 | /// TODO Move this list inside `updateDecl` where it should be allocated |
| 162 | /// prior to calling `generateSymbol`, and then immediately deallocated | 163 | /// prior to calling `generateSymbol`, and then immediately deallocated |
| 163 | /// rather than sitting in the global scope. | 164 | /// rather than sitting in the global scope. |
| 164 | pie_fixups: std.ArrayListUnmanaged(PieFixup) = .{}, | 165 | /// TODO We should also rewrite this using generic relocations common to all |
| | 166 | /// backends. |
| | 167 | pie_fixups: std.ArrayListUnmanaged(PIEFixup) = .{}, |
| | 168 | |
| 165 | /// A list of all stub (extern decls) fixups required for this run of the linker. | 169 | /// A list of all stub (extern decls) fixups required for this run of the linker. |
| 166 | /// Warning, this is currently NOT thread-safe. See the TODO below. | 170 | /// Warning, this is currently NOT thread-safe. See the TODO below. |
| 167 | /// TODO Move this list inside `updateDecl` where it should be allocated | 171 | /// TODO Move this list inside `updateDecl` where it should be allocated |
| ... | @@ -169,14 +173,42 @@ pie_fixups: std.ArrayListUnmanaged(PieFixup) = .{}, | ... | @@ -169,14 +173,42 @@ pie_fixups: std.ArrayListUnmanaged(PieFixup) = .{}, |
| 169 | /// rather than sitting in the global scope. | 173 | /// rather than sitting in the global scope. |
| 170 | stub_fixups: std.ArrayListUnmanaged(StubFixup) = .{}, | 174 | stub_fixups: std.ArrayListUnmanaged(StubFixup) = .{}, |
| 171 | | 175 | |
| 172 | pub const PieFixup = struct { | 176 | pub const GOTEntry = struct { |
| 173 | /// Target address we wanted to address in absolute terms. | 177 | /// GOT entry can either be a local pointer or an extern (nonlazy) import. |
| 174 | address: u64, | 178 | kind: enum { |
| 175 | /// Where in the byte stream we should perform the fixup. | 179 | Local, |
| 176 | start: usize, | 180 | Extern, |
| 177 | /// The length of the byte stream. For x86_64, this will be | 181 | }, |
| 178 | /// variable. For aarch64, it will be fixed at 4 bytes. | 182 | |
| 179 | len: usize, | 183 | /// Id to the macho.nlist_64 from the respective table: either locals or nonlazy imports. |
| | 184 | /// TODO I'm more and more inclined to just manage a single, max two symbol tables |
| | 185 | /// rather than 4 as we currently do, but I'll follow up in the future PR. |
| | 186 | symbol: u32, |
| | 187 | |
| | 188 | /// Index of this entry in the GOT. |
| | 189 | index: u32, |
| | 190 | }; |
| | 191 | |
| | 192 | pub const Import = struct { |
| | 193 | /// MachO symbol table entry. |
| | 194 | symbol: macho.nlist_64, |
| | 195 | |
| | 196 | /// Id of the dynamic library where the specified entries can be found. |
| | 197 | dylib_ordinal: i64, |
| | 198 | |
| | 199 | /// Index of this import within the import list. |
| | 200 | index: u32, |
| | 201 | }; |
| | 202 | |
| | 203 | pub const PIEFixup = struct { |
| | 204 | /// Target VM address of this relocation. |
| | 205 | target_addr: u64, |
| | 206 | |
| | 207 | /// Offset within the byte stream. |
| | 208 | offset: usize, |
| | 209 | |
| | 210 | /// Size of the relocation. |
| | 211 | size: usize, |
| 180 | }; | 212 | }; |
| 181 | | 213 | |
| 182 | pub const StubFixup = struct { | 214 | pub const StubFixup = struct { |
| ... | @@ -260,9 +292,9 @@ pub const TextBlock = struct { | ... | @@ -260,9 +292,9 @@ pub const TextBlock = struct { |
| 260 | /// File offset relocation happens transparently, so it is not included in | 292 | /// File offset relocation happens transparently, so it is not included in |
| 261 | /// this calculation. | 293 | /// this calculation. |
| 262 | fn capacity(self: TextBlock, macho_file: MachO) u64 { | 294 | fn capacity(self: TextBlock, macho_file: MachO) u64 { |
| 263 | const self_sym = macho_file.local_symbols.items[self.local_sym_index]; | 295 | const self_sym = macho_file.locals.items[self.local_sym_index]; |
| 264 | if (self.next) |next| { | 296 | if (self.next) |next| { |
| 265 | const next_sym = macho_file.local_symbols.items[next.local_sym_index]; | 297 | const next_sym = macho_file.locals.items[next.local_sym_index]; |
| 266 | return next_sym.n_value - self_sym.n_value; | 298 | return next_sym.n_value - self_sym.n_value; |
| 267 | } else { | 299 | } else { |
| 268 | // We are the last block. | 300 | // We are the last block. |
| ... | @@ -274,8 +306,8 @@ pub const TextBlock = struct { | ... | @@ -274,8 +306,8 @@ pub const TextBlock = struct { |
| 274 | fn freeListEligible(self: TextBlock, macho_file: MachO) bool { | 306 | fn freeListEligible(self: TextBlock, macho_file: MachO) bool { |
| 275 | // No need to keep a free list node for the last block. | 307 | // No need to keep a free list node for the last block. |
| 276 | const next = self.next orelse return false; | 308 | const next = self.next orelse return false; |
| 277 | const self_sym = macho_file.local_symbols.items[self.local_sym_index]; | 309 | const self_sym = macho_file.locals.items[self.local_sym_index]; |
| 278 | const next_sym = macho_file.local_symbols.items[next.local_sym_index]; | 310 | const next_sym = macho_file.locals.items[next.local_sym_index]; |
| 279 | const cap = next_sym.n_value - self_sym.n_value; | 311 | const cap = next_sym.n_value - self_sym.n_value; |
| 280 | const ideal_cap = padToIdeal(self.size); | 312 | const ideal_cap = padToIdeal(self.size); |
| 281 | if (cap <= ideal_cap) return false; | 313 | if (cap <= ideal_cap) return false; |
| ... | @@ -344,7 +376,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio | ... | @@ -344,7 +376,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio |
| 344 | }; | 376 | }; |
| 345 | | 377 | |
| 346 | // Index 0 is always a null symbol. | 378 | // Index 0 is always a null symbol. |
| 347 | try self.local_symbols.append(allocator, .{ | 379 | try self.locals.append(allocator, .{ |
| 348 | .n_strx = 0, | 380 | .n_strx = 0, |
| 349 | .n_type = 0, | 381 | .n_type = 0, |
| 350 | .n_sect = 0, | 382 | .n_sect = 0, |
| ... | @@ -834,7 +866,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { | ... | @@ -834,7 +866,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 834 | } | 866 | } |
| 835 | }, | 867 | }, |
| 836 | else => { | 868 | else => { |
| 837 | log.err("{s} terminated", .{ argv.items[0] }); | 869 | log.err("{s} terminated", .{argv.items[0]}); |
| 838 | return error.LLDCrashed; | 870 | return error.LLDCrashed; |
| 839 | }, | 871 | }, |
| 840 | } | 872 | } |
| ... | @@ -1019,14 +1051,14 @@ pub fn deinit(self: *MachO) void { | ... | @@ -1019,14 +1051,14 @@ pub fn deinit(self: *MachO) void { |
| 1019 | if (self.d_sym) |*ds| { | 1051 | if (self.d_sym) |*ds| { |
| 1020 | ds.deinit(self.base.allocator); | 1052 | ds.deinit(self.base.allocator); |
| 1021 | } | 1053 | } |
| 1022 | for (self.extern_lazy_symbols.items()) |*entry| { | 1054 | for (self.lazy_imports.items()) |*entry| { |
| 1023 | self.base.allocator.free(entry.key); | 1055 | self.base.allocator.free(entry.key); |
| 1024 | } | 1056 | } |
| 1025 | self.extern_lazy_symbols.deinit(self.base.allocator); | 1057 | self.lazy_imports.deinit(self.base.allocator); |
| 1026 | for (self.extern_nonlazy_symbols.items()) |*entry| { | 1058 | for (self.nonlazy_imports.items()) |*entry| { |
| 1027 | self.base.allocator.free(entry.key); | 1059 | self.base.allocator.free(entry.key); |
| 1028 | } | 1060 | } |
| 1029 | self.extern_nonlazy_symbols.deinit(self.base.allocator); | 1061 | self.nonlazy_imports.deinit(self.base.allocator); |
| 1030 | self.pie_fixups.deinit(self.base.allocator); | 1062 | self.pie_fixups.deinit(self.base.allocator); |
| 1031 | self.stub_fixups.deinit(self.base.allocator); | 1063 | self.stub_fixups.deinit(self.base.allocator); |
| 1032 | self.text_block_free_list.deinit(self.base.allocator); | 1064 | self.text_block_free_list.deinit(self.base.allocator); |
| ... | @@ -1040,10 +1072,10 @@ pub fn deinit(self: *MachO) void { | ... | @@ -1040,10 +1072,10 @@ pub fn deinit(self: *MachO) void { |
| 1040 | } | 1072 | } |
| 1041 | self.string_table_directory.deinit(self.base.allocator); | 1073 | self.string_table_directory.deinit(self.base.allocator); |
| 1042 | self.string_table.deinit(self.base.allocator); | 1074 | self.string_table.deinit(self.base.allocator); |
| 1043 | self.global_symbols.deinit(self.base.allocator); | 1075 | self.globals.deinit(self.base.allocator); |
| 1044 | self.global_symbol_free_list.deinit(self.base.allocator); | 1076 | self.globals_free_list.deinit(self.base.allocator); |
| 1045 | self.local_symbols.deinit(self.base.allocator); | 1077 | self.locals.deinit(self.base.allocator); |
| 1046 | self.local_symbol_free_list.deinit(self.base.allocator); | 1078 | self.locals_free_list.deinit(self.base.allocator); |
| 1047 | for (self.load_commands.items) |*lc| { | 1079 | for (self.load_commands.items) |*lc| { |
| 1048 | lc.deinit(self.base.allocator); | 1080 | lc.deinit(self.base.allocator); |
| 1049 | } | 1081 | } |
| ... | @@ -1098,7 +1130,7 @@ fn shrinkTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64) vo | ... | @@ -1098,7 +1130,7 @@ fn shrinkTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64) vo |
| 1098 | } | 1130 | } |
| 1099 | | 1131 | |
| 1100 | fn growTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 { | 1132 | fn growTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 { |
| 1101 | const sym = self.local_symbols.items[text_block.local_sym_index]; | 1133 | const sym = self.locals.items[text_block.local_sym_index]; |
| 1102 | const align_ok = mem.alignBackwardGeneric(u64, sym.n_value, alignment) == sym.n_value; | 1134 | const align_ok = mem.alignBackwardGeneric(u64, sym.n_value, alignment) == sym.n_value; |
| 1103 | const need_realloc = !align_ok or new_block_size > text_block.capacity(self.*); | 1135 | const need_realloc = !align_ok or new_block_size > text_block.capacity(self.*); |
| 1104 | if (!need_realloc) return sym.n_value; | 1136 | if (!need_realloc) return sym.n_value; |
| ... | @@ -1108,34 +1140,41 @@ fn growTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, alig | ... | @@ -1108,34 +1140,41 @@ fn growTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, alig |
| 1108 | pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void { | 1140 | pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void { |
| 1109 | if (decl.link.macho.local_sym_index != 0) return; | 1141 | if (decl.link.macho.local_sym_index != 0) return; |
| 1110 | | 1142 | |
| 1111 | try self.local_symbols.ensureCapacity(self.base.allocator, self.local_symbols.items.len + 1); | 1143 | try self.locals.ensureCapacity(self.base.allocator, self.locals.items.len + 1); |
| 1112 | try self.offset_table.ensureCapacity(self.base.allocator, self.offset_table.items.len + 1); | 1144 | try self.offset_table.ensureCapacity(self.base.allocator, self.offset_table.items.len + 1); |
| 1113 | | 1145 | |
| 1114 | if (self.local_symbol_free_list.popOrNull()) |i| { | 1146 | if (self.locals_free_list.popOrNull()) |i| { |
| 1115 | log.debug("reusing symbol index {d} for {s}", .{ i, decl.name }); | 1147 | log.debug("reusing symbol index {d} for {s}", .{ i, decl.name }); |
| 1116 | decl.link.macho.local_sym_index = i; | 1148 | decl.link.macho.local_sym_index = i; |
| 1117 | } else { | 1149 | } else { |
| 1118 | log.debug("allocating symbol index {d} for {s}", .{ self.local_symbols.items.len, decl.name }); | 1150 | log.debug("allocating symbol index {d} for {s}", .{ self.locals.items.len, decl.name }); |
| 1119 | decl.link.macho.local_sym_index = @intCast(u32, self.local_symbols.items.len); | 1151 | decl.link.macho.local_sym_index = @intCast(u32, self.locals.items.len); |
| 1120 | _ = self.local_symbols.addOneAssumeCapacity(); | 1152 | _ = self.locals.addOneAssumeCapacity(); |
| 1121 | } | 1153 | } |
| 1122 | | 1154 | |
| 1123 | if (self.offset_table_free_list.popOrNull()) |i| { | 1155 | if (self.offset_table_free_list.popOrNull()) |i| { |
| | 1156 | log.debug("reusing offset table entry index {d} for {s}", .{ i, decl.name }); |
| 1124 | decl.link.macho.offset_table_index = i; | 1157 | decl.link.macho.offset_table_index = i; |
| 1125 | } else { | 1158 | } else { |
| | 1159 | log.debug("allocating offset table entry index {d} for {s}", .{ self.offset_table.items.len, decl.name }); |
| 1126 | decl.link.macho.offset_table_index = @intCast(u32, self.offset_table.items.len); | 1160 | decl.link.macho.offset_table_index = @intCast(u32, self.offset_table.items.len); |
| 1127 | _ = self.offset_table.addOneAssumeCapacity(); | 1161 | _ = self.offset_table.addOneAssumeCapacity(); |
| 1128 | self.offset_table_count_dirty = true; | 1162 | self.offset_table_count_dirty = true; |
| | 1163 | self.rebase_info_dirty = true; |
| 1129 | } | 1164 | } |
| 1130 | | 1165 | |
| 1131 | self.local_symbols.items[decl.link.macho.local_sym_index] = .{ | 1166 | self.locals.items[decl.link.macho.local_sym_index] = .{ |
| 1132 | .n_strx = 0, | 1167 | .n_strx = 0, |
| 1133 | .n_type = 0, | 1168 | .n_type = 0, |
| 1134 | .n_sect = 0, | 1169 | .n_sect = 0, |
| 1135 | .n_desc = 0, | 1170 | .n_desc = 0, |
| 1136 | .n_value = 0, | 1171 | .n_value = 0, |
| 1137 | }; | 1172 | }; |
| 1138 | self.offset_table.items[decl.link.macho.offset_table_index] = 0; | 1173 | self.offset_table.items[decl.link.macho.offset_table_index] = .{ |
| | 1174 | .kind = .Local, |
| | 1175 | .symbol = decl.link.macho.local_sym_index, |
| | 1176 | .index = decl.link.macho.offset_table_index, |
| | 1177 | }; |
| 1139 | } | 1178 | } |
| 1140 | | 1179 | |
| 1141 | pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { | 1180 | pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| ... | @@ -1178,8 +1217,9 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { | ... | @@ -1178,8 +1217,9 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 1178 | .externally_managed => |x| x, | 1217 | .externally_managed => |x| x, |
| 1179 | .appended => code_buffer.items, | 1218 | .appended => code_buffer.items, |
| 1180 | .fail => |em| { | 1219 | .fail => |em| { |
| 1181 | // Clear any PIE fixups and stub fixups for this decl. | 1220 | // Clear any PIE fixups for this decl. |
| 1182 | self.pie_fixups.shrinkRetainingCapacity(0); | 1221 | self.pie_fixups.shrinkRetainingCapacity(0); |
| | 1222 | // Clear any stub fixups for this decl. |
| 1183 | self.stub_fixups.shrinkRetainingCapacity(0); | 1223 | self.stub_fixups.shrinkRetainingCapacity(0); |
| 1184 | decl.analysis = .codegen_failure; | 1224 | decl.analysis = .codegen_failure; |
| 1185 | try module.failed_decls.put(module.gpa, decl, em); | 1225 | try module.failed_decls.put(module.gpa, decl, em); |
| ... | @@ -1189,7 +1229,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { | ... | @@ -1189,7 +1229,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 1189 | | 1229 | |
| 1190 | const required_alignment = typed_value.ty.abiAlignment(self.base.options.target); | 1230 | const required_alignment = typed_value.ty.abiAlignment(self.base.options.target); |
| 1191 | assert(decl.link.macho.local_sym_index != 0); // Caller forgot to call allocateDeclIndexes() | 1231 | assert(decl.link.macho.local_sym_index != 0); // Caller forgot to call allocateDeclIndexes() |
| 1192 | const symbol = &self.local_symbols.items[decl.link.macho.local_sym_index]; | 1232 | const symbol = &self.locals.items[decl.link.macho.local_sym_index]; |
| 1193 | | 1233 | |
| 1194 | if (decl.link.macho.size != 0) { | 1234 | if (decl.link.macho.size != 0) { |
| 1195 | const capacity = decl.link.macho.capacity(self.*); | 1235 | const capacity = decl.link.macho.capacity(self.*); |
| ... | @@ -1198,9 +1238,12 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { | ... | @@ -1198,9 +1238,12 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 1198 | const vaddr = try self.growTextBlock(&decl.link.macho, code.len, required_alignment); | 1238 | const vaddr = try self.growTextBlock(&decl.link.macho, code.len, required_alignment); |
| 1199 | log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl.name, symbol.n_value, vaddr }); | 1239 | log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl.name, symbol.n_value, vaddr }); |
| 1200 | if (vaddr != symbol.n_value) { | 1240 | if (vaddr != symbol.n_value) { |
| 1201 | symbol.n_value = vaddr; | | |
| 1202 | log.debug(" (writing new offset table entry)", .{}); | 1241 | log.debug(" (writing new offset table entry)", .{}); |
| 1203 | self.offset_table.items[decl.link.macho.offset_table_index] = vaddr; | 1242 | self.offset_table.items[decl.link.macho.offset_table_index] = .{ |
| | 1243 | .kind = .Local, |
| | 1244 | .symbol = decl.link.macho.local_sym_index, |
| | 1245 | .index = decl.link.macho.offset_table_index, |
| | 1246 | }; |
| 1204 | try self.writeOffsetTableEntry(decl.link.macho.offset_table_index); | 1247 | try self.writeOffsetTableEntry(decl.link.macho.offset_table_index); |
| 1205 | } | 1248 | } |
| 1206 | } else if (code.len < decl.link.macho.size) { | 1249 | } else if (code.len < decl.link.macho.size) { |
| ... | @@ -1229,7 +1272,11 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { | ... | @@ -1229,7 +1272,11 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 1229 | .n_desc = 0, | 1272 | .n_desc = 0, |
| 1230 | .n_value = addr, | 1273 | .n_value = addr, |
| 1231 | }; | 1274 | }; |
| 1232 | self.offset_table.items[decl.link.macho.offset_table_index] = addr; | 1275 | self.offset_table.items[decl.link.macho.offset_table_index] = .{ |
| | 1276 | .kind = .Local, |
| | 1277 | .symbol = decl.link.macho.local_sym_index, |
| | 1278 | .index = decl.link.macho.offset_table_index, |
| | 1279 | }; |
| 1233 | | 1280 | |
| 1234 | try self.writeLocalSymbol(decl.link.macho.local_sym_index); | 1281 | try self.writeLocalSymbol(decl.link.macho.local_sym_index); |
| 1235 | if (self.d_sym) |*ds| | 1282 | if (self.d_sym) |*ds| |
| ... | @@ -1237,30 +1284,48 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { | ... | @@ -1237,30 +1284,48 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 1237 | try self.writeOffsetTableEntry(decl.link.macho.offset_table_index); | 1284 | try self.writeOffsetTableEntry(decl.link.macho.offset_table_index); |
| 1238 | } | 1285 | } |
| 1239 | | 1286 | |
| 1240 | // Perform PIE fixups (if any) | 1287 | // Calculate displacements to target addr (if any). |
| 1241 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; | | |
| 1242 | const got_section = text_segment.sections.items[self.got_section_index.?]; | | |
| 1243 | while (self.pie_fixups.popOrNull()) |fixup| { | 1288 | while (self.pie_fixups.popOrNull()) |fixup| { |
| 1244 | const target_addr = fixup.address; | 1289 | assert(fixup.size == 4); |
| 1245 | const this_addr = symbol.n_value + fixup.start; | 1290 | const this_addr = symbol.n_value + fixup.offset; |
| | 1291 | const target_addr = fixup.target_addr; |
| | 1292 | |
| 1246 | switch (self.base.options.target.cpu.arch) { | 1293 | switch (self.base.options.target.cpu.arch) { |
| 1247 | .x86_64 => { | 1294 | .x86_64 => { |
| 1248 | assert(target_addr >= this_addr + fixup.len); | 1295 | const displacement = try math.cast(u32, target_addr - this_addr - 4); |
| 1249 | const displacement = try math.cast(u32, target_addr - this_addr - fixup.len); | 1296 | mem.writeIntLittle(u32, code_buffer.items[fixup.offset..][0..4], displacement); |
| 1250 | var placeholder = code_buffer.items[fixup.start + fixup.len - @sizeOf(u32) ..][0..@sizeOf(u32)]; | | |
| 1251 | mem.writeIntSliceLittle(u32, placeholder, displacement); | | |
| 1252 | }, | 1297 | }, |
| 1253 | .aarch64 => { | 1298 | .aarch64 => { |
| 1254 | assert(target_addr >= this_addr); | 1299 | // TODO optimize instruction based on jump length (use ldr(literal) + nop if possible). |
| 1255 | const displacement = try math.cast(u27, target_addr - this_addr); | 1300 | { |
| 1256 | var placeholder = code_buffer.items[fixup.start..][0..fixup.len]; | 1301 | const inst = code_buffer.items[fixup.offset..][0..4]; |
| 1257 | mem.writeIntSliceLittle(u32, placeholder, aarch64.Instruction.b(@as(i28, displacement)).toU32()); | 1302 | var parsed = mem.bytesAsValue(meta.TagPayload( |
| | 1303 | aarch64.Instruction, |
| | 1304 | aarch64.Instruction.PCRelativeAddress, |
| | 1305 | ), inst); |
| | 1306 | const this_page = @intCast(i32, this_addr >> 12); |
| | 1307 | const target_page = @intCast(i32, target_addr >> 12); |
| | 1308 | const pages = @bitCast(u21, @intCast(i21, target_page - this_page)); |
| | 1309 | parsed.immhi = @truncate(u19, pages >> 2); |
| | 1310 | parsed.immlo = @truncate(u2, pages); |
| | 1311 | } |
| | 1312 | { |
| | 1313 | const inst = code_buffer.items[fixup.offset + 4 ..][0..4]; |
| | 1314 | var parsed = mem.bytesAsValue(meta.TagPayload( |
| | 1315 | aarch64.Instruction, |
| | 1316 | aarch64.Instruction.LoadStoreRegister, |
| | 1317 | ), inst); |
| | 1318 | const narrowed = @truncate(u12, target_addr); |
| | 1319 | const offset = try math.divExact(u12, narrowed, 8); |
| | 1320 | parsed.offset = offset; |
| | 1321 | } |
| 1258 | }, | 1322 | }, |
| 1259 | else => unreachable, // unsupported target architecture | 1323 | else => unreachable, // unsupported target architecture |
| 1260 | } | 1324 | } |
| 1261 | } | 1325 | } |
| 1262 | | 1326 | |
| 1263 | // Resolve stubs (if any) | 1327 | // Resolve stubs (if any) |
| | 1328 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 1264 | const stubs = text_segment.sections.items[self.stubs_section_index.?]; | 1329 | const stubs = text_segment.sections.items[self.stubs_section_index.?]; |
| 1265 | for (self.stub_fixups.items) |fixup| { | 1330 | for (self.stub_fixups.items) |fixup| { |
| 1266 | const stub_addr = stubs.addr + fixup.symbol * stubs.reserved2; | 1331 | const stub_addr = stubs.addr + fixup.symbol * stubs.reserved2; |
| ... | @@ -1285,9 +1350,6 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { | ... | @@ -1285,9 +1350,6 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 1285 | try self.writeStubInStubHelper(fixup.symbol); | 1350 | try self.writeStubInStubHelper(fixup.symbol); |
| 1286 | try self.writeLazySymbolPointer(fixup.symbol); | 1351 | try self.writeLazySymbolPointer(fixup.symbol); |
| 1287 | | 1352 | |
| 1288 | const extern_sym = &self.extern_lazy_symbols.items()[fixup.symbol].value; | | |
| 1289 | extern_sym.segment = self.data_segment_cmd_index.?; | | |
| 1290 | extern_sym.offset = fixup.symbol * @sizeOf(u64); | | |
| 1291 | self.rebase_info_dirty = true; | 1353 | self.rebase_info_dirty = true; |
| 1292 | self.lazy_binding_info_dirty = true; | 1354 | self.lazy_binding_info_dirty = true; |
| 1293 | } | 1355 | } |
| ... | @@ -1329,9 +1391,9 @@ pub fn updateDeclExports( | ... | @@ -1329,9 +1391,9 @@ pub fn updateDeclExports( |
| 1329 | const tracy = trace(@src()); | 1391 | const tracy = trace(@src()); |
| 1330 | defer tracy.end(); | 1392 | defer tracy.end(); |
| 1331 | | 1393 | |
| 1332 | try self.global_symbols.ensureCapacity(self.base.allocator, self.global_symbols.items.len + exports.len); | 1394 | try self.globals.ensureCapacity(self.base.allocator, self.globals.items.len + exports.len); |
| 1333 | if (decl.link.macho.local_sym_index == 0) return; | 1395 | if (decl.link.macho.local_sym_index == 0) return; |
| 1334 | const decl_sym = &self.local_symbols.items[decl.link.macho.local_sym_index]; | 1396 | const decl_sym = &self.locals.items[decl.link.macho.local_sym_index]; |
| 1335 | | 1397 | |
| 1336 | for (exports) |exp| { | 1398 | for (exports) |exp| { |
| 1337 | if (exp.options.section) |section_name| { | 1399 | if (exp.options.section) |section_name| { |
| ... | @@ -1364,7 +1426,7 @@ pub fn updateDeclExports( | ... | @@ -1364,7 +1426,7 @@ pub fn updateDeclExports( |
| 1364 | }; | 1426 | }; |
| 1365 | const n_type = decl_sym.n_type | macho.N_EXT; | 1427 | const n_type = decl_sym.n_type | macho.N_EXT; |
| 1366 | if (exp.link.macho.sym_index) |i| { | 1428 | if (exp.link.macho.sym_index) |i| { |
| 1367 | const sym = &self.global_symbols.items[i]; | 1429 | const sym = &self.globals.items[i]; |
| 1368 | sym.* = .{ | 1430 | sym.* = .{ |
| 1369 | .n_strx = try self.updateString(sym.n_strx, exp.options.name), | 1431 | .n_strx = try self.updateString(sym.n_strx, exp.options.name), |
| 1370 | .n_type = n_type, | 1432 | .n_type = n_type, |
| ... | @@ -1374,12 +1436,12 @@ pub fn updateDeclExports( | ... | @@ -1374,12 +1436,12 @@ pub fn updateDeclExports( |
| 1374 | }; | 1436 | }; |
| 1375 | } else { | 1437 | } else { |
| 1376 | const name_str_index = try self.makeString(exp.options.name); | 1438 | const name_str_index = try self.makeString(exp.options.name); |
| 1377 | const i = if (self.global_symbol_free_list.popOrNull()) |i| i else blk: { | 1439 | const i = if (self.globals_free_list.popOrNull()) |i| i else blk: { |
| 1378 | _ = self.global_symbols.addOneAssumeCapacity(); | 1440 | _ = self.globals.addOneAssumeCapacity(); |
| 1379 | self.export_info_dirty = true; | 1441 | self.export_info_dirty = true; |
| 1380 | break :blk self.global_symbols.items.len - 1; | 1442 | break :blk self.globals.items.len - 1; |
| 1381 | }; | 1443 | }; |
| 1382 | self.global_symbols.items[i] = .{ | 1444 | self.globals.items[i] = .{ |
| 1383 | .n_strx = name_str_index, | 1445 | .n_strx = name_str_index, |
| 1384 | .n_type = n_type, | 1446 | .n_type = n_type, |
| 1385 | .n_sect = @intCast(u8, self.text_section_index.?) + 1, | 1447 | .n_sect = @intCast(u8, self.text_section_index.?) + 1, |
| ... | @@ -1394,18 +1456,18 @@ pub fn updateDeclExports( | ... | @@ -1394,18 +1456,18 @@ pub fn updateDeclExports( |
| 1394 | | 1456 | |
| 1395 | pub fn deleteExport(self: *MachO, exp: Export) void { | 1457 | pub fn deleteExport(self: *MachO, exp: Export) void { |
| 1396 | const sym_index = exp.sym_index orelse return; | 1458 | const sym_index = exp.sym_index orelse return; |
| 1397 | self.global_symbol_free_list.append(self.base.allocator, sym_index) catch {}; | 1459 | self.globals_free_list.append(self.base.allocator, sym_index) catch {}; |
| 1398 | self.global_symbols.items[sym_index].n_type = 0; | 1460 | self.globals.items[sym_index].n_type = 0; |
| 1399 | } | 1461 | } |
| 1400 | | 1462 | |
| 1401 | pub fn freeDecl(self: *MachO, decl: *Module.Decl) void { | 1463 | pub fn freeDecl(self: *MachO, decl: *Module.Decl) void { |
| 1402 | // Appending to free lists is allowed to fail because the free lists are heuristics based anyway. | 1464 | // Appending to free lists is allowed to fail because the free lists are heuristics based anyway. |
| 1403 | self.freeTextBlock(&decl.link.macho); | 1465 | self.freeTextBlock(&decl.link.macho); |
| 1404 | if (decl.link.macho.local_sym_index != 0) { | 1466 | if (decl.link.macho.local_sym_index != 0) { |
| 1405 | self.local_symbol_free_list.append(self.base.allocator, decl.link.macho.local_sym_index) catch {}; | 1467 | self.locals_free_list.append(self.base.allocator, decl.link.macho.local_sym_index) catch {}; |
| 1406 | self.offset_table_free_list.append(self.base.allocator, decl.link.macho.offset_table_index) catch {}; | 1468 | self.offset_table_free_list.append(self.base.allocator, decl.link.macho.offset_table_index) catch {}; |
| 1407 | | 1469 | |
| 1408 | self.local_symbols.items[decl.link.macho.local_sym_index].n_type = 0; | 1470 | self.locals.items[decl.link.macho.local_sym_index].n_type = 0; |
| 1409 | | 1471 | |
| 1410 | decl.link.macho.local_sym_index = 0; | 1472 | decl.link.macho.local_sym_index = 0; |
| 1411 | } | 1473 | } |
| ... | @@ -1413,7 +1475,7 @@ pub fn freeDecl(self: *MachO, decl: *Module.Decl) void { | ... | @@ -1413,7 +1475,7 @@ pub fn freeDecl(self: *MachO, decl: *Module.Decl) void { |
| 1413 | | 1475 | |
| 1414 | pub fn getDeclVAddr(self: *MachO, decl: *const Module.Decl) u64 { | 1476 | pub fn getDeclVAddr(self: *MachO, decl: *const Module.Decl) u64 { |
| 1415 | assert(decl.link.macho.local_sym_index != 0); | 1477 | assert(decl.link.macho.local_sym_index != 0); |
| 1416 | return self.local_symbols.items[decl.link.macho.local_sym_index].n_value; | 1478 | return self.locals.items[decl.link.macho.local_sym_index].n_value; |
| 1417 | } | 1479 | } |
| 1418 | | 1480 | |
| 1419 | pub fn populateMissingMetadata(self: *MachO) !void { | 1481 | pub fn populateMissingMetadata(self: *MachO) !void { |
| ... | @@ -1553,39 +1615,6 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1553,39 +1615,6 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1553 | self.header_dirty = true; | 1615 | self.header_dirty = true; |
| 1554 | self.load_commands_dirty = true; | 1616 | self.load_commands_dirty = true; |
| 1555 | } | 1617 | } |
| 1556 | if (self.got_section_index == null) { | | |
| 1557 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; | | |
| 1558 | self.got_section_index = @intCast(u16, text_segment.sections.items.len); | | |
| 1559 | | | |
| 1560 | const alignment: u2 = switch (self.base.options.target.cpu.arch) { | | |
| 1561 | .x86_64 => 0, | | |
| 1562 | .aarch64 => 2, | | |
| 1563 | else => unreachable, // unhandled architecture type | | |
| 1564 | }; | | |
| 1565 | const flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS; | | |
| 1566 | const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint; | | |
| 1567 | const off = text_segment.findFreeSpace(needed_size, @alignOf(u64), self.header_pad); | | |
| 1568 | assert(off + needed_size <= text_segment.inner.fileoff + text_segment.inner.filesize); // TODO Must expand __TEXT segment. | | |
| 1569 | | | |
| 1570 | log.debug("found __ziggot section free space 0x{x} to 0x{x}", .{ off, off + needed_size }); | | |
| 1571 | | | |
| 1572 | try text_segment.addSection(self.base.allocator, .{ | | |
| 1573 | .sectname = makeStaticString("__ziggot"), | | |
| 1574 | .segname = makeStaticString("__TEXT"), | | |
| 1575 | .addr = text_segment.inner.vmaddr + off, | | |
| 1576 | .size = needed_size, | | |
| 1577 | .offset = @intCast(u32, off), | | |
| 1578 | .@"align" = alignment, | | |
| 1579 | .reloff = 0, | | |
| 1580 | .nreloc = 0, | | |
| 1581 | .flags = flags, | | |
| 1582 | .reserved1 = 0, | | |
| 1583 | .reserved2 = 0, | | |
| 1584 | .reserved3 = 0, | | |
| 1585 | }); | | |
| 1586 | self.header_dirty = true; | | |
| 1587 | self.load_commands_dirty = true; | | |
| 1588 | } | | |
| 1589 | if (self.stubs_section_index == null) { | 1618 | if (self.stubs_section_index == null) { |
| 1590 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 1619 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 1591 | self.stubs_section_index = @intCast(u16, text_segment.sections.items.len); | 1620 | self.stubs_section_index = @intCast(u16, text_segment.sections.items.len); |
| ... | @@ -1597,7 +1626,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1597,7 +1626,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1597 | }; | 1626 | }; |
| 1598 | const stub_size: u4 = switch (self.base.options.target.cpu.arch) { | 1627 | const stub_size: u4 = switch (self.base.options.target.cpu.arch) { |
| 1599 | .x86_64 => 6, | 1628 | .x86_64 => 6, |
| 1600 | .aarch64 => 2 * @sizeOf(u32), | 1629 | .aarch64 => 3 * @sizeOf(u32), |
| 1601 | else => unreachable, // unhandled architecture type | 1630 | else => unreachable, // unhandled architecture type |
| 1602 | }; | 1631 | }; |
| 1603 | const flags = macho.S_SYMBOL_STUBS | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS; | 1632 | const flags = macho.S_SYMBOL_STUBS | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS; |
| ... | @@ -1686,9 +1715,9 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1686,9 +1715,9 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1686 | self.header_dirty = true; | 1715 | self.header_dirty = true; |
| 1687 | self.load_commands_dirty = true; | 1716 | self.load_commands_dirty = true; |
| 1688 | } | 1717 | } |
| 1689 | if (self.data_got_section_index == null) { | 1718 | if (self.got_section_index == null) { |
| 1690 | const dc_segment = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; | 1719 | const dc_segment = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| 1691 | self.data_got_section_index = @intCast(u16, dc_segment.sections.items.len); | 1720 | self.got_section_index = @intCast(u16, dc_segment.sections.items.len); |
| 1692 | | 1721 | |
| 1693 | const flags = macho.S_NON_LAZY_SYMBOL_POINTERS; | 1722 | const flags = macho.S_NON_LAZY_SYMBOL_POINTERS; |
| 1694 | const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint; | 1723 | const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint; |
| ... | @@ -2060,12 +2089,12 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -2060,12 +2089,12 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 2060 | self.header_dirty = true; | 2089 | self.header_dirty = true; |
| 2061 | self.load_commands_dirty = true; | 2090 | self.load_commands_dirty = true; |
| 2062 | } | 2091 | } |
| 2063 | if (!self.extern_nonlazy_symbols.contains("dyld_stub_binder")) { | 2092 | if (!self.nonlazy_imports.contains("dyld_stub_binder")) { |
| 2064 | const index = @intCast(u32, self.extern_nonlazy_symbols.items().len); | 2093 | const index = @intCast(u32, self.nonlazy_imports.items().len); |
| 2065 | const name = try self.base.allocator.dupe(u8, "dyld_stub_binder"); | 2094 | const name = try self.base.allocator.dupe(u8, "dyld_stub_binder"); |
| 2066 | const offset = try self.makeString("dyld_stub_binder"); | 2095 | const offset = try self.makeString("dyld_stub_binder"); |
| 2067 | try self.extern_nonlazy_symbols.putNoClobber(self.base.allocator, name, .{ | 2096 | try self.nonlazy_imports.putNoClobber(self.base.allocator, name, .{ |
| 2068 | .inner = .{ | 2097 | .symbol = .{ |
| 2069 | .n_strx = offset, | 2098 | .n_strx = offset, |
| 2070 | .n_type = std.macho.N_UNDF | std.macho.N_EXT, | 2099 | .n_type = std.macho.N_UNDF | std.macho.N_EXT, |
| 2071 | .n_sect = 0, | 2100 | .n_sect = 0, |
| ... | @@ -2073,68 +2102,19 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -2073,68 +2102,19 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 2073 | .n_value = 0, | 2102 | .n_value = 0, |
| 2074 | }, | 2103 | }, |
| 2075 | .dylib_ordinal = 1, // TODO this is currently hardcoded. | 2104 | .dylib_ordinal = 1, // TODO this is currently hardcoded. |
| 2076 | .segment = self.data_const_segment_cmd_index.?, | 2105 | .index = index, |
| 2077 | .offset = index * @sizeOf(u64), | | |
| 2078 | }); | 2106 | }); |
| | 2107 | const off_index = @intCast(u32, self.offset_table.items.len); |
| | 2108 | try self.offset_table.append(self.base.allocator, .{ |
| | 2109 | .kind = .Extern, |
| | 2110 | .symbol = index, |
| | 2111 | .index = off_index, |
| | 2112 | }); |
| | 2113 | try self.writeOffsetTableEntry(off_index); |
| 2079 | self.binding_info_dirty = true; | 2114 | self.binding_info_dirty = true; |
| 2080 | } | 2115 | } |
| 2081 | if (self.stub_helper_stubs_start_off == null) { | 2116 | if (self.stub_helper_stubs_start_off == null) { |
| 2082 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 2117 | try self.writeStubHelperPreamble(); |
| 2083 | const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?]; | | |
| 2084 | const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; | | |
| 2085 | const data = &data_segment.sections.items[self.data_section_index.?]; | | |
| 2086 | const data_const_segment = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; | | |
| 2087 | const got = &data_const_segment.sections.items[self.data_got_section_index.?]; | | |
| 2088 | switch (self.base.options.target.cpu.arch) { | | |
| 2089 | .x86_64 => { | | |
| 2090 | const code_size = 15; | | |
| 2091 | var code: [code_size]u8 = undefined; | | |
| 2092 | // lea %r11, [rip + disp] | | |
| 2093 | code[0] = 0x4c; | | |
| 2094 | code[1] = 0x8d; | | |
| 2095 | code[2] = 0x1d; | | |
| 2096 | { | | |
| 2097 | const displacement = try math.cast(u32, data.addr - stub_helper.addr - 7); | | |
| 2098 | mem.writeIntLittle(u32, code[3..7], displacement); | | |
| 2099 | } | | |
| 2100 | // push %r11 | | |
| 2101 | code[7] = 0x41; | | |
| 2102 | code[8] = 0x53; | | |
| 2103 | // jmp [rip + disp] | | |
| 2104 | code[9] = 0xff; | | |
| 2105 | code[10] = 0x25; | | |
| 2106 | { | | |
| 2107 | const displacement = try math.cast(u32, got.addr - stub_helper.addr - code_size); | | |
| 2108 | mem.writeIntLittle(u32, code[11..], displacement); | | |
| 2109 | } | | |
| 2110 | self.stub_helper_stubs_start_off = stub_helper.offset + code_size; | | |
| 2111 | try self.base.file.?.pwriteAll(&code, stub_helper.offset); | | |
| 2112 | }, | | |
| 2113 | .aarch64 => { | | |
| 2114 | var code: [4 * @sizeOf(u32)]u8 = undefined; | | |
| 2115 | { | | |
| 2116 | const displacement = try math.cast(i21, data.addr - stub_helper.addr); | | |
| 2117 | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.adr(.x17, displacement).toU32()); | | |
| 2118 | } | | |
| 2119 | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.stp( | | |
| 2120 | .x16, | | |
| 2121 | .x17, | | |
| 2122 | aarch64.Register.sp, | | |
| 2123 | aarch64.Instruction.LoadStorePairOffset.pre_index(-16), | | |
| 2124 | ).toU32()); | | |
| 2125 | { | | |
| 2126 | const displacement = try math.divExact(u64, got.addr - stub_helper.addr - 2 * @sizeOf(u32), 4); | | |
| 2127 | const literal = try math.cast(u19, displacement); | | |
| 2128 | mem.writeIntLittle(u32, code[8..12], aarch64.Instruction.ldr(.x16, .{ | | |
| 2129 | .literal = literal, | | |
| 2130 | }).toU32()); | | |
| 2131 | } | | |
| 2132 | mem.writeIntLittle(u32, code[12..16], aarch64.Instruction.br(.x16).toU32()); | | |
| 2133 | self.stub_helper_stubs_start_off = stub_helper.offset + 4 * @sizeOf(u32); | | |
| 2134 | try self.base.file.?.pwriteAll(&code, stub_helper.offset); | | |
| 2135 | }, | | |
| 2136 | else => unreachable, | | |
| 2137 | } | | |
| 2138 | } | 2118 | } |
| 2139 | } | 2119 | } |
| 2140 | | 2120 | |
| ... | @@ -2159,7 +2139,7 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, | ... | @@ -2159,7 +2139,7 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, |
| 2159 | const big_block = self.text_block_free_list.items[i]; | 2139 | const big_block = self.text_block_free_list.items[i]; |
| 2160 | // We now have a pointer to a live text block that has too much capacity. | 2140 | // We now have a pointer to a live text block that has too much capacity. |
| 2161 | // Is it enough that we could fit this new text block? | 2141 | // Is it enough that we could fit this new text block? |
| 2162 | const sym = self.local_symbols.items[big_block.local_sym_index]; | 2142 | const sym = self.locals.items[big_block.local_sym_index]; |
| 2163 | const capacity = big_block.capacity(self.*); | 2143 | const capacity = big_block.capacity(self.*); |
| 2164 | const ideal_capacity = padToIdeal(capacity); | 2144 | const ideal_capacity = padToIdeal(capacity); |
| 2165 | const ideal_capacity_end_vaddr = sym.n_value + ideal_capacity; | 2145 | const ideal_capacity_end_vaddr = sym.n_value + ideal_capacity; |
| ... | @@ -2190,7 +2170,7 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, | ... | @@ -2190,7 +2170,7 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, |
| 2190 | } | 2170 | } |
| 2191 | break :blk new_start_vaddr; | 2171 | break :blk new_start_vaddr; |
| 2192 | } else if (self.last_text_block) |last| { | 2172 | } else if (self.last_text_block) |last| { |
| 2193 | const last_symbol = self.local_symbols.items[last.local_sym_index]; | 2173 | const last_symbol = self.locals.items[last.local_sym_index]; |
| 2194 | // TODO We should pad out the excess capacity with NOPs. For executables, | 2174 | // TODO We should pad out the excess capacity with NOPs. For executables, |
| 2195 | // no padding seems to be OK, but it will probably not be for objects. | 2175 | // no padding seems to be OK, but it will probably not be for objects. |
| 2196 | const ideal_capacity = padToIdeal(last.size); | 2176 | const ideal_capacity = padToIdeal(last.size); |
| ... | @@ -2288,12 +2268,12 @@ fn updateString(self: *MachO, old_str_off: u32, new_name: []const u8) !u32 { | ... | @@ -2288,12 +2268,12 @@ fn updateString(self: *MachO, old_str_off: u32, new_name: []const u8) !u32 { |
| 2288 | } | 2268 | } |
| 2289 | | 2269 | |
| 2290 | pub fn addExternSymbol(self: *MachO, name: []const u8) !u32 { | 2270 | pub fn addExternSymbol(self: *MachO, name: []const u8) !u32 { |
| 2291 | const index = @intCast(u32, self.extern_lazy_symbols.items().len); | 2271 | const index = @intCast(u32, self.lazy_imports.items().len); |
| 2292 | const offset = try self.makeString(name); | 2272 | const offset = try self.makeString(name); |
| 2293 | const sym_name = try self.base.allocator.dupe(u8, name); | 2273 | const sym_name = try self.base.allocator.dupe(u8, name); |
| 2294 | const dylib_ordinal = 1; // TODO this is now hardcoded, since we only support libSystem. | 2274 | const dylib_ordinal = 1; // TODO this is now hardcoded, since we only support libSystem. |
| 2295 | try self.extern_lazy_symbols.putNoClobber(self.base.allocator, sym_name, .{ | 2275 | try self.lazy_imports.putNoClobber(self.base.allocator, sym_name, .{ |
| 2296 | .inner = .{ | 2276 | .symbol = .{ |
| 2297 | .n_strx = offset, | 2277 | .n_strx = offset, |
| 2298 | .n_type = macho.N_UNDF | macho.N_EXT, | 2278 | .n_type = macho.N_UNDF | macho.N_EXT, |
| 2299 | .n_sect = 0, | 2279 | .n_sect = 0, |
| ... | @@ -2301,6 +2281,7 @@ pub fn addExternSymbol(self: *MachO, name: []const u8) !u32 { | ... | @@ -2301,6 +2281,7 @@ pub fn addExternSymbol(self: *MachO, name: []const u8) !u32 { |
| 2301 | .n_value = 0, | 2281 | .n_value = 0, |
| 2302 | }, | 2282 | }, |
| 2303 | .dylib_ordinal = dylib_ordinal, | 2283 | .dylib_ordinal = dylib_ordinal, |
| | 2284 | .index = index, |
| 2304 | }); | 2285 | }); |
| 2305 | log.debug("adding new extern symbol '{s}' with dylib ordinal '{}'", .{ name, dylib_ordinal }); | 2286 | log.debug("adding new extern symbol '{s}' with dylib ordinal '{}'", .{ name, dylib_ordinal }); |
| 2306 | return index; | 2287 | return index; |
| ... | @@ -2459,41 +2440,29 @@ fn findFreeSpaceLinkedit(self: *MachO, object_size: u64, min_alignment: u16, sta | ... | @@ -2459,41 +2440,29 @@ fn findFreeSpaceLinkedit(self: *MachO, object_size: u64, min_alignment: u16, sta |
| 2459 | } | 2440 | } |
| 2460 | | 2441 | |
| 2461 | fn writeOffsetTableEntry(self: *MachO, index: usize) !void { | 2442 | fn writeOffsetTableEntry(self: *MachO, index: usize) !void { |
| 2462 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 2443 | const seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| 2463 | const sect = &text_segment.sections.items[self.got_section_index.?]; | 2444 | const sect = &seg.sections.items[self.got_section_index.?]; |
| 2464 | const off = sect.offset + @sizeOf(u64) * index; | 2445 | const off = sect.offset + @sizeOf(u64) * index; |
| 2465 | const vmaddr = sect.addr + @sizeOf(u64) * index; | | |
| 2466 | | 2446 | |
| 2467 | if (self.offset_table_count_dirty) { | 2447 | if (self.offset_table_count_dirty) { |
| 2468 | // TODO relocate. | 2448 | // TODO relocate. |
| 2469 | self.offset_table_count_dirty = false; | 2449 | self.offset_table_count_dirty = false; |
| 2470 | } | 2450 | } |
| 2471 | | 2451 | |
| 2472 | var code: [8]u8 = undefined; | 2452 | const got_entry = self.offset_table.items[index]; |
| 2473 | switch (self.base.options.target.cpu.arch) { | 2453 | const sym = blk: { |
| 2474 | .x86_64 => { | 2454 | switch (got_entry.kind) { |
| 2475 | const pos_symbol_off = try math.cast(u31, vmaddr - self.offset_table.items[index] + 7); | 2455 | .Local => { |
| 2476 | const symbol_off = @bitCast(u32, @as(i32, pos_symbol_off) * -1); | 2456 | break :blk self.locals.items[got_entry.symbol]; |
| 2477 | // lea %rax, [rip - disp] | 2457 | }, |
| 2478 | code[0] = 0x48; | 2458 | .Extern => { |
| 2479 | code[1] = 0x8D; | 2459 | break :blk self.nonlazy_imports.items()[got_entry.symbol].value.symbol; |
| 2480 | code[2] = 0x5; | 2460 | }, |
| 2481 | mem.writeIntLittle(u32, code[3..7], symbol_off); | 2461 | } |
| 2482 | // ret | 2462 | }; |
| 2483 | code[7] = 0xC3; | 2463 | const sym_name = self.getString(sym.n_strx); |
| 2484 | }, | 2464 | log.debug("writing offset table entry [ 0x{x} => 0x{x} ({s}) ]", .{ off, sym.n_value, sym_name }); |
| 2485 | .aarch64 => { | 2465 | try self.base.file.?.pwriteAll(mem.asBytes(&sym.n_value), off); |
| 2486 | const pos_symbol_off = try math.cast(u20, vmaddr - self.offset_table.items[index]); | | |
| 2487 | const symbol_off = @as(i21, pos_symbol_off) * -1; | | |
| 2488 | // adr x0, #-disp | | |
| 2489 | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.adr(.x0, symbol_off).toU32()); | | |
| 2490 | // ret x28 | | |
| 2491 | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.ret(.x28).toU32()); | | |
| 2492 | }, | | |
| 2493 | else => unreachable, // unsupported target architecture | | |
| 2494 | } | | |
| 2495 | log.debug("writing offset table entry 0x{x} at 0x{x}", .{ self.offset_table.items[index], off }); | | |
| 2496 | try self.base.file.?.pwriteAll(&code, off); | | |
| 2497 | } | 2466 | } |
| 2498 | | 2467 | |
| 2499 | fn writeLazySymbolPointer(self: *MachO, index: u32) !void { | 2468 | fn writeLazySymbolPointer(self: *MachO, index: u32) !void { |
| ... | @@ -2516,6 +2485,133 @@ fn writeLazySymbolPointer(self: *MachO, index: u32) !void { | ... | @@ -2516,6 +2485,133 @@ fn writeLazySymbolPointer(self: *MachO, index: u32) !void { |
| 2516 | try self.base.file.?.pwriteAll(&buf, off); | 2485 | try self.base.file.?.pwriteAll(&buf, off); |
| 2517 | } | 2486 | } |
| 2518 | | 2487 | |
| | 2488 | fn writeStubHelperPreamble(self: *MachO) !void { |
| | 2489 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| | 2490 | const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?]; |
| | 2491 | const data_const_segment = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| | 2492 | const got = &data_const_segment.sections.items[self.got_section_index.?]; |
| | 2493 | const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| | 2494 | const data = &data_segment.sections.items[self.data_section_index.?]; |
| | 2495 | |
| | 2496 | switch (self.base.options.target.cpu.arch) { |
| | 2497 | .x86_64 => { |
| | 2498 | const code_size = 15; |
| | 2499 | var code: [code_size]u8 = undefined; |
| | 2500 | // lea %r11, [rip + disp] |
| | 2501 | code[0] = 0x4c; |
| | 2502 | code[1] = 0x8d; |
| | 2503 | code[2] = 0x1d; |
| | 2504 | { |
| | 2505 | const target_addr = data.addr; |
| | 2506 | const displacement = try math.cast(u32, target_addr - stub_helper.addr - 7); |
| | 2507 | mem.writeIntLittle(u32, code[3..7], displacement); |
| | 2508 | } |
| | 2509 | // push %r11 |
| | 2510 | code[7] = 0x41; |
| | 2511 | code[8] = 0x53; |
| | 2512 | // jmp [rip + disp] |
| | 2513 | code[9] = 0xff; |
| | 2514 | code[10] = 0x25; |
| | 2515 | { |
| | 2516 | const displacement = try math.cast(u32, got.addr - stub_helper.addr - code_size); |
| | 2517 | mem.writeIntLittle(u32, code[11..], displacement); |
| | 2518 | } |
| | 2519 | try self.base.file.?.pwriteAll(&code, stub_helper.offset); |
| | 2520 | self.stub_helper_stubs_start_off = stub_helper.offset + code_size; |
| | 2521 | }, |
| | 2522 | .aarch64 => { |
| | 2523 | var code: [6 * @sizeOf(u32)]u8 = undefined; |
| | 2524 | |
| | 2525 | data_blk_outer: { |
| | 2526 | const this_addr = stub_helper.addr; |
| | 2527 | const target_addr = data.addr; |
| | 2528 | data_blk: { |
| | 2529 | const displacement = math.cast(i21, target_addr - this_addr) catch |_| break :data_blk; |
| | 2530 | // adr x17, disp |
| | 2531 | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.adr(.x17, displacement).toU32()); |
| | 2532 | // nop |
| | 2533 | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.nop().toU32()); |
| | 2534 | break :data_blk_outer; |
| | 2535 | } |
| | 2536 | data_blk: { |
| | 2537 | const new_this_addr = this_addr + @sizeOf(u32); |
| | 2538 | const displacement = math.cast(i21, target_addr - new_this_addr) catch |_| break :data_blk; |
| | 2539 | // nop |
| | 2540 | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.nop().toU32()); |
| | 2541 | // adr x17, disp |
| | 2542 | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.adr(.x17, displacement).toU32()); |
| | 2543 | break :data_blk_outer; |
| | 2544 | } |
| | 2545 | // Jump is too big, replace adr with adrp and add. |
| | 2546 | const this_page = @intCast(i32, this_addr >> 12); |
| | 2547 | const target_page = @intCast(i32, target_addr >> 12); |
| | 2548 | const pages = @intCast(i21, target_page - this_page); |
| | 2549 | // adrp x17, pages |
| | 2550 | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.adrp(.x17, pages).toU32()); |
| | 2551 | const narrowed = @truncate(u12, target_addr); |
| | 2552 | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.add(.x17, .x17, narrowed, false).toU32()); |
| | 2553 | } |
| | 2554 | |
| | 2555 | // stp x16, x17, [sp, #-16]! |
| | 2556 | mem.writeIntLittle(u32, code[8..12], aarch64.Instruction.stp( |
| | 2557 | .x16, |
| | 2558 | .x17, |
| | 2559 | aarch64.Register.sp, |
| | 2560 | aarch64.Instruction.LoadStorePairOffset.pre_index(-16), |
| | 2561 | ).toU32()); |
| | 2562 | |
| | 2563 | binder_blk_outer: { |
| | 2564 | const this_addr = stub_helper.addr + 3 * @sizeOf(u32); |
| | 2565 | const target_addr = got.addr; |
| | 2566 | binder_blk: { |
| | 2567 | const displacement = math.divExact(u64, target_addr - this_addr, 4) catch |_| break :binder_blk; |
| | 2568 | const literal = math.cast(u18, displacement) catch |_| break :binder_blk; |
| | 2569 | // ldr x16, label |
| | 2570 | mem.writeIntLittle(u32, code[12..16], aarch64.Instruction.ldr(.x16, .{ |
| | 2571 | .literal = literal, |
| | 2572 | }).toU32()); |
| | 2573 | // nop |
| | 2574 | mem.writeIntLittle(u32, code[16..20], aarch64.Instruction.nop().toU32()); |
| | 2575 | break :binder_blk_outer; |
| | 2576 | } |
| | 2577 | binder_blk: { |
| | 2578 | const new_this_addr = this_addr + @sizeOf(u32); |
| | 2579 | const displacement = math.divExact(u64, target_addr - new_this_addr, 4) catch |_| break :binder_blk; |
| | 2580 | const literal = math.cast(u18, displacement) catch |_| break :binder_blk; |
| | 2581 | // nop |
| | 2582 | mem.writeIntLittle(u32, code[12..16], aarch64.Instruction.nop().toU32()); |
| | 2583 | // ldr x16, label |
| | 2584 | mem.writeIntLittle(u32, code[16..20], aarch64.Instruction.ldr(.x16, .{ |
| | 2585 | .literal = literal, |
| | 2586 | }).toU32()); |
| | 2587 | break :binder_blk_outer; |
| | 2588 | } |
| | 2589 | // Jump is too big, replace ldr with adrp and ldr(register). |
| | 2590 | const this_page = @intCast(i32, this_addr >> 12); |
| | 2591 | const target_page = @intCast(i32, target_addr >> 12); |
| | 2592 | const pages = @intCast(i21, target_page - this_page); |
| | 2593 | // adrp x16, pages |
| | 2594 | mem.writeIntLittle(u32, code[12..16], aarch64.Instruction.adrp(.x16, pages).toU32()); |
| | 2595 | const narrowed = @truncate(u12, target_addr); |
| | 2596 | const offset = try math.divExact(u12, narrowed, 8); |
| | 2597 | // ldr x16, x16, offset |
| | 2598 | mem.writeIntLittle(u32, code[16..20], aarch64.Instruction.ldr(.x16, .{ |
| | 2599 | .register = .{ |
| | 2600 | .rn = .x16, |
| | 2601 | .offset = aarch64.Instruction.LoadStoreOffset.imm(offset), |
| | 2602 | }, |
| | 2603 | }).toU32()); |
| | 2604 | } |
| | 2605 | |
| | 2606 | // br x16 |
| | 2607 | mem.writeIntLittle(u32, code[20..24], aarch64.Instruction.br(.x16).toU32()); |
| | 2608 | try self.base.file.?.pwriteAll(&code, stub_helper.offset); |
| | 2609 | self.stub_helper_stubs_start_off = stub_helper.offset + code.len; |
| | 2610 | }, |
| | 2611 | else => unreachable, |
| | 2612 | } |
| | 2613 | } |
| | 2614 | |
| 2519 | fn writeStub(self: *MachO, index: u32) !void { | 2615 | fn writeStub(self: *MachO, index: u32) !void { |
| 2520 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 2616 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 2521 | const stubs = text_segment.sections.items[self.stubs_section_index.?]; | 2617 | const stubs = text_segment.sections.items[self.stubs_section_index.?]; |
| ... | @@ -2525,9 +2621,12 @@ fn writeStub(self: *MachO, index: u32) !void { | ... | @@ -2525,9 +2621,12 @@ fn writeStub(self: *MachO, index: u32) !void { |
| 2525 | const stub_off = stubs.offset + index * stubs.reserved2; | 2621 | const stub_off = stubs.offset + index * stubs.reserved2; |
| 2526 | const stub_addr = stubs.addr + index * stubs.reserved2; | 2622 | const stub_addr = stubs.addr + index * stubs.reserved2; |
| 2527 | const la_ptr_addr = la_symbol_ptr.addr + index * @sizeOf(u64); | 2623 | const la_ptr_addr = la_symbol_ptr.addr + index * @sizeOf(u64); |
| | 2624 | |
| 2528 | log.debug("writing stub at 0x{x}", .{stub_off}); | 2625 | log.debug("writing stub at 0x{x}", .{stub_off}); |
| | 2626 | |
| 2529 | var code = try self.base.allocator.alloc(u8, stubs.reserved2); | 2627 | var code = try self.base.allocator.alloc(u8, stubs.reserved2); |
| 2530 | defer self.base.allocator.free(code); | 2628 | defer self.base.allocator.free(code); |
| | 2629 | |
| 2531 | switch (self.base.options.target.cpu.arch) { | 2630 | switch (self.base.options.target.cpu.arch) { |
| 2532 | .x86_64 => { | 2631 | .x86_64 => { |
| 2533 | assert(la_ptr_addr >= stub_addr + stubs.reserved2); | 2632 | assert(la_ptr_addr >= stub_addr + stubs.reserved2); |
| ... | @@ -2539,12 +2638,50 @@ fn writeStub(self: *MachO, index: u32) !void { | ... | @@ -2539,12 +2638,50 @@ fn writeStub(self: *MachO, index: u32) !void { |
| 2539 | }, | 2638 | }, |
| 2540 | .aarch64 => { | 2639 | .aarch64 => { |
| 2541 | assert(la_ptr_addr >= stub_addr); | 2640 | assert(la_ptr_addr >= stub_addr); |
| 2542 | const displacement = try math.divExact(u64, la_ptr_addr - stub_addr, 4); | 2641 | outer: { |
| 2543 | const literal = try math.cast(u19, displacement); | 2642 | const this_addr = stub_addr; |
| 2544 | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.ldr(.x16, .{ | 2643 | const target_addr = la_ptr_addr; |
| 2545 | .literal = literal, | 2644 | inner: { |
| 2546 | }).toU32()); | 2645 | const displacement = math.divExact(u64, target_addr - this_addr, 4) catch |_| break :inner; |
| 2547 | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.br(.x16).toU32()); | 2646 | const literal = math.cast(u18, displacement) catch |_| break :inner; |
| | 2647 | // ldr x16, literal |
| | 2648 | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.ldr(.x16, .{ |
| | 2649 | .literal = literal, |
| | 2650 | }).toU32()); |
| | 2651 | // nop |
| | 2652 | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.nop().toU32()); |
| | 2653 | break :outer; |
| | 2654 | } |
| | 2655 | inner: { |
| | 2656 | const new_this_addr = this_addr + @sizeOf(u32); |
| | 2657 | const displacement = math.divExact(u64, target_addr - new_this_addr, 4) catch |_| break :inner; |
| | 2658 | const literal = math.cast(u18, displacement) catch |_| break :inner; |
| | 2659 | // nop |
| | 2660 | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.nop().toU32()); |
| | 2661 | // ldr x16, literal |
| | 2662 | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.ldr(.x16, .{ |
| | 2663 | .literal = literal, |
| | 2664 | }).toU32()); |
| | 2665 | break :outer; |
| | 2666 | } |
| | 2667 | // Use adrp followed by ldr(register). |
| | 2668 | const this_page = @intCast(i32, this_addr >> 12); |
| | 2669 | const target_page = @intCast(i32, target_addr >> 12); |
| | 2670 | const pages = @intCast(i21, target_page - this_page); |
| | 2671 | // adrp x16, pages |
| | 2672 | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.adrp(.x16, pages).toU32()); |
| | 2673 | const narrowed = @truncate(u12, target_addr); |
| | 2674 | const offset = try math.divExact(u12, narrowed, 8); |
| | 2675 | // ldr x16, x16, offset |
| | 2676 | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.ldr(.x16, .{ |
| | 2677 | .register = .{ |
| | 2678 | .rn = .x16, |
| | 2679 | .offset = aarch64.Instruction.LoadStoreOffset.imm(offset), |
| | 2680 | }, |
| | 2681 | }).toU32()); |
| | 2682 | } |
| | 2683 | // br x16 |
| | 2684 | mem.writeIntLittle(u32, code[8..12], aarch64.Instruction.br(.x16).toU32()); |
| 2548 | }, | 2685 | }, |
| 2549 | else => unreachable, | 2686 | else => unreachable, |
| 2550 | } | 2687 | } |
| ... | @@ -2561,8 +2698,10 @@ fn writeStubInStubHelper(self: *MachO, index: u32) !void { | ... | @@ -2561,8 +2698,10 @@ fn writeStubInStubHelper(self: *MachO, index: u32) !void { |
| 2561 | else => unreachable, | 2698 | else => unreachable, |
| 2562 | }; | 2699 | }; |
| 2563 | const stub_off = self.stub_helper_stubs_start_off.? + index * stub_size; | 2700 | const stub_off = self.stub_helper_stubs_start_off.? + index * stub_size; |
| | 2701 | |
| 2564 | var code = try self.base.allocator.alloc(u8, stub_size); | 2702 | var code = try self.base.allocator.alloc(u8, stub_size); |
| 2565 | defer self.base.allocator.free(code); | 2703 | defer self.base.allocator.free(code); |
| | 2704 | |
| 2566 | switch (self.base.options.target.cpu.arch) { | 2705 | switch (self.base.options.target.cpu.arch) { |
| 2567 | .x86_64 => { | 2706 | .x86_64 => { |
| 2568 | const displacement = try math.cast( | 2707 | const displacement = try math.cast( |
| ... | @@ -2577,12 +2716,19 @@ fn writeStubInStubHelper(self: *MachO, index: u32) !void { | ... | @@ -2577,12 +2716,19 @@ fn writeStubInStubHelper(self: *MachO, index: u32) !void { |
| 2577 | mem.writeIntLittle(u32, code[6..][0..4], @bitCast(u32, displacement)); | 2716 | mem.writeIntLittle(u32, code[6..][0..4], @bitCast(u32, displacement)); |
| 2578 | }, | 2717 | }, |
| 2579 | .aarch64 => { | 2718 | .aarch64 => { |
| 2580 | const displacement = try math.cast(i28, @intCast(i64, stub_helper.offset) - @intCast(i64, stub_off) - 4); | 2719 | const literal = blk: { |
| | 2720 | const div_res = try math.divExact(u64, stub_size - @sizeOf(u32), 4); |
| | 2721 | break :blk try math.cast(u18, div_res); |
| | 2722 | }; |
| | 2723 | // ldr w16, literal |
| 2581 | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.ldr(.w16, .{ | 2724 | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.ldr(.w16, .{ |
| 2582 | .literal = @divExact(stub_size - @sizeOf(u32), 4), | 2725 | .literal = literal, |
| 2583 | }).toU32()); | 2726 | }).toU32()); |
| | 2727 | const displacement = try math.cast(i28, @intCast(i64, stub_helper.offset) - @intCast(i64, stub_off) - 4); |
| | 2728 | // b disp |
| 2584 | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.b(displacement).toU32()); | 2729 | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.b(displacement).toU32()); |
| 2585 | mem.writeIntLittle(u32, code[8..12], 0x0); // Just a placeholder populated in `populateLazyBindOffsetsInStubHelper`. | 2730 | // Just a placeholder populated in `populateLazyBindOffsetsInStubHelper`. |
| | 2731 | mem.writeIntLittle(u32, code[8..12], 0x0); |
| 2586 | }, | 2732 | }, |
| 2587 | else => unreachable, | 2733 | else => unreachable, |
| 2588 | } | 2734 | } |
| ... | @@ -2591,9 +2737,9 @@ fn writeStubInStubHelper(self: *MachO, index: u32) !void { | ... | @@ -2591,9 +2737,9 @@ fn writeStubInStubHelper(self: *MachO, index: u32) !void { |
| 2591 | | 2737 | |
| 2592 | fn relocateSymbolTable(self: *MachO) !void { | 2738 | fn relocateSymbolTable(self: *MachO) !void { |
| 2593 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; | 2739 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; |
| 2594 | const nlocals = self.local_symbols.items.len; | 2740 | const nlocals = self.locals.items.len; |
| 2595 | const nglobals = self.global_symbols.items.len; | 2741 | const nglobals = self.globals.items.len; |
| 2596 | const nundefs = self.extern_lazy_symbols.items().len + self.extern_nonlazy_symbols.items().len; | 2742 | const nundefs = self.lazy_imports.items().len + self.nonlazy_imports.items().len; |
| 2597 | const nsyms = nlocals + nglobals + nundefs; | 2743 | const nsyms = nlocals + nglobals + nundefs; |
| 2598 | | 2744 | |
| 2599 | if (symtab.nsyms < nsyms) { | 2745 | if (symtab.nsyms < nsyms) { |
| ... | @@ -2628,7 +2774,7 @@ fn writeLocalSymbol(self: *MachO, index: usize) !void { | ... | @@ -2628,7 +2774,7 @@ fn writeLocalSymbol(self: *MachO, index: usize) !void { |
| 2628 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; | 2774 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; |
| 2629 | const off = symtab.symoff + @sizeOf(macho.nlist_64) * index; | 2775 | const off = symtab.symoff + @sizeOf(macho.nlist_64) * index; |
| 2630 | log.debug("writing local symbol {} at 0x{x}", .{ index, off }); | 2776 | log.debug("writing local symbol {} at 0x{x}", .{ index, off }); |
| 2631 | try self.base.file.?.pwriteAll(mem.asBytes(&self.local_symbols.items[index]), off); | 2777 | try self.base.file.?.pwriteAll(mem.asBytes(&self.locals.items[index]), off); |
| 2632 | } | 2778 | } |
| 2633 | | 2779 | |
| 2634 | fn writeAllGlobalAndUndefSymbols(self: *MachO) !void { | 2780 | fn writeAllGlobalAndUndefSymbols(self: *MachO) !void { |
| ... | @@ -2637,18 +2783,18 @@ fn writeAllGlobalAndUndefSymbols(self: *MachO) !void { | ... | @@ -2637,18 +2783,18 @@ fn writeAllGlobalAndUndefSymbols(self: *MachO) !void { |
| 2637 | | 2783 | |
| 2638 | try self.relocateSymbolTable(); | 2784 | try self.relocateSymbolTable(); |
| 2639 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; | 2785 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; |
| 2640 | const nlocals = self.local_symbols.items.len; | 2786 | const nlocals = self.locals.items.len; |
| 2641 | const nglobals = self.global_symbols.items.len; | 2787 | const nglobals = self.globals.items.len; |
| 2642 | | 2788 | |
| 2643 | const nundefs = self.extern_lazy_symbols.items().len + self.extern_nonlazy_symbols.items().len; | 2789 | const nundefs = self.lazy_imports.items().len + self.nonlazy_imports.items().len; |
| 2644 | var undefs = std.ArrayList(macho.nlist_64).init(self.base.allocator); | 2790 | var undefs = std.ArrayList(macho.nlist_64).init(self.base.allocator); |
| 2645 | defer undefs.deinit(); | 2791 | defer undefs.deinit(); |
| 2646 | try undefs.ensureCapacity(nundefs); | 2792 | try undefs.ensureCapacity(nundefs); |
| 2647 | for (self.extern_lazy_symbols.items()) |entry| { | 2793 | for (self.lazy_imports.items()) |entry| { |
| 2648 | undefs.appendAssumeCapacity(entry.value.inner); | 2794 | undefs.appendAssumeCapacity(entry.value.symbol); |
| 2649 | } | 2795 | } |
| 2650 | for (self.extern_nonlazy_symbols.items()) |entry| { | 2796 | for (self.nonlazy_imports.items()) |entry| { |
| 2651 | undefs.appendAssumeCapacity(entry.value.inner); | 2797 | undefs.appendAssumeCapacity(entry.value.symbol); |
| 2652 | } | 2798 | } |
| 2653 | | 2799 | |
| 2654 | const locals_off = symtab.symoff; | 2800 | const locals_off = symtab.symoff; |
| ... | @@ -2657,7 +2803,7 @@ fn writeAllGlobalAndUndefSymbols(self: *MachO) !void { | ... | @@ -2657,7 +2803,7 @@ fn writeAllGlobalAndUndefSymbols(self: *MachO) !void { |
| 2657 | const globals_off = locals_off + locals_size; | 2803 | const globals_off = locals_off + locals_size; |
| 2658 | const globals_size = nglobals * @sizeOf(macho.nlist_64); | 2804 | const globals_size = nglobals * @sizeOf(macho.nlist_64); |
| 2659 | log.debug("writing global symbols from 0x{x} to 0x{x}", .{ globals_off, globals_size + globals_off }); | 2805 | log.debug("writing global symbols from 0x{x} to 0x{x}", .{ globals_off, globals_size + globals_off }); |
| 2660 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.global_symbols.items), globals_off); | 2806 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.globals.items), globals_off); |
| 2661 | | 2807 | |
| 2662 | const undefs_off = globals_off + globals_size; | 2808 | const undefs_off = globals_off + globals_size; |
| 2663 | const undefs_size = nundefs * @sizeOf(macho.nlist_64); | 2809 | const undefs_size = nundefs * @sizeOf(macho.nlist_64); |
| ... | @@ -2683,15 +2829,15 @@ fn writeIndirectSymbolTable(self: *MachO) !void { | ... | @@ -2683,15 +2829,15 @@ fn writeIndirectSymbolTable(self: *MachO) !void { |
| 2683 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 2829 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 2684 | const stubs = &text_segment.sections.items[self.stubs_section_index.?]; | 2830 | const stubs = &text_segment.sections.items[self.stubs_section_index.?]; |
| 2685 | const data_const_seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; | 2831 | const data_const_seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| 2686 | const got = &data_const_seg.sections.items[self.data_got_section_index.?]; | 2832 | const got = &data_const_seg.sections.items[self.got_section_index.?]; |
| 2687 | const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; | 2833 | const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 2688 | const la_symbol_ptr = &data_segment.sections.items[self.la_symbol_ptr_section_index.?]; | 2834 | const la_symbol_ptr = &data_segment.sections.items[self.la_symbol_ptr_section_index.?]; |
| 2689 | const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab; | 2835 | const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab; |
| 2690 | | 2836 | |
| 2691 | const lazy = self.extern_lazy_symbols.items(); | 2837 | const lazy = self.lazy_imports.items(); |
| 2692 | const nonlazy = self.extern_nonlazy_symbols.items(); | 2838 | const got_entries = self.offset_table.items; |
| 2693 | const allocated_size = self.allocatedSizeLinkedit(dysymtab.indirectsymoff); | 2839 | const allocated_size = self.allocatedSizeLinkedit(dysymtab.indirectsymoff); |
| 2694 | const nindirectsyms = @intCast(u32, lazy.len * 2 + nonlazy.len); | 2840 | const nindirectsyms = @intCast(u32, lazy.len * 2 + got_entries.len); |
| 2695 | const needed_size = @intCast(u32, nindirectsyms * @sizeOf(u32)); | 2841 | const needed_size = @intCast(u32, nindirectsyms * @sizeOf(u32)); |
| 2696 | | 2842 | |
| 2697 | if (needed_size > allocated_size) { | 2843 | if (needed_size > allocated_size) { |
| ... | @@ -2710,20 +2856,27 @@ fn writeIndirectSymbolTable(self: *MachO) !void { | ... | @@ -2710,20 +2856,27 @@ fn writeIndirectSymbolTable(self: *MachO) !void { |
| 2710 | var writer = stream.writer(); | 2856 | var writer = stream.writer(); |
| 2711 | | 2857 | |
| 2712 | stubs.reserved1 = 0; | 2858 | stubs.reserved1 = 0; |
| 2713 | for (self.extern_lazy_symbols.items()) |_, i| { | 2859 | for (lazy) |_, i| { |
| 2714 | const symtab_idx = @intCast(u32, dysymtab.iundefsym + i); | 2860 | const symtab_idx = @intCast(u32, dysymtab.iundefsym + i); |
| 2715 | try writer.writeIntLittle(u32, symtab_idx); | 2861 | try writer.writeIntLittle(u32, symtab_idx); |
| 2716 | } | 2862 | } |
| 2717 | | 2863 | |
| 2718 | const base_id = @intCast(u32, lazy.len); | 2864 | const base_id = @intCast(u32, lazy.len); |
| 2719 | got.reserved1 = base_id; | 2865 | got.reserved1 = base_id; |
| 2720 | for (self.extern_nonlazy_symbols.items()) |_, i| { | 2866 | for (got_entries) |entry| { |
| 2721 | const symtab_idx = @intCast(u32, dysymtab.iundefsym + i + base_id); | 2867 | switch (entry.kind) { |
| 2722 | try writer.writeIntLittle(u32, symtab_idx); | 2868 | .Local => { |
| | 2869 | try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL); |
| | 2870 | }, |
| | 2871 | .Extern => { |
| | 2872 | const symtab_idx = @intCast(u32, dysymtab.iundefsym + entry.index + base_id); |
| | 2873 | try writer.writeIntLittle(u32, symtab_idx); |
| | 2874 | }, |
| | 2875 | } |
| 2723 | } | 2876 | } |
| 2724 | | 2877 | |
| 2725 | la_symbol_ptr.reserved1 = got.reserved1 + @intCast(u32, nonlazy.len); | 2878 | la_symbol_ptr.reserved1 = got.reserved1 + @intCast(u32, got_entries.len); |
| 2726 | for (self.extern_lazy_symbols.items()) |_, i| { | 2879 | for (lazy) |_, i| { |
| 2727 | const symtab_idx = @intCast(u32, dysymtab.iundefsym + i); | 2880 | const symtab_idx = @intCast(u32, dysymtab.iundefsym + i); |
| 2728 | try writer.writeIntLittle(u32, symtab_idx); | 2881 | try writer.writeIntLittle(u32, symtab_idx); |
| 2729 | } | 2882 | } |
| ... | @@ -2789,7 +2942,7 @@ fn writeCodeSignature(self: *MachO) !void { | ... | @@ -2789,7 +2942,7 @@ fn writeCodeSignature(self: *MachO) !void { |
| 2789 | | 2942 | |
| 2790 | fn writeExportTrie(self: *MachO) !void { | 2943 | fn writeExportTrie(self: *MachO) !void { |
| 2791 | if (!self.export_info_dirty) return; | 2944 | if (!self.export_info_dirty) return; |
| 2792 | if (self.global_symbols.items.len == 0) return; | 2945 | if (self.globals.items.len == 0) return; |
| 2793 | | 2946 | |
| 2794 | const tracy = trace(@src()); | 2947 | const tracy = trace(@src()); |
| 2795 | defer tracy.end(); | 2948 | defer tracy.end(); |
| ... | @@ -2798,7 +2951,7 @@ fn writeExportTrie(self: *MachO) !void { | ... | @@ -2798,7 +2951,7 @@ fn writeExportTrie(self: *MachO) !void { |
| 2798 | defer trie.deinit(); | 2951 | defer trie.deinit(); |
| 2799 | | 2952 | |
| 2800 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 2953 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 2801 | for (self.global_symbols.items) |symbol| { | 2954 | for (self.globals.items) |symbol| { |
| 2802 | // TODO figure out if we should put all global symbols into the export trie | 2955 | // TODO figure out if we should put all global symbols into the export trie |
| 2803 | const name = self.getString(symbol.n_strx); | 2956 | const name = self.getString(symbol.n_strx); |
| 2804 | assert(symbol.n_value >= text_segment.inner.vmaddr); | 2957 | assert(symbol.n_value >= text_segment.inner.vmaddr); |
| ... | @@ -2840,14 +2993,48 @@ fn writeRebaseInfoTable(self: *MachO) !void { | ... | @@ -2840,14 +2993,48 @@ fn writeRebaseInfoTable(self: *MachO) !void { |
| 2840 | const tracy = trace(@src()); | 2993 | const tracy = trace(@src()); |
| 2841 | defer tracy.end(); | 2994 | defer tracy.end(); |
| 2842 | | 2995 | |
| 2843 | const size = try rebaseInfoSize(self.extern_lazy_symbols.items()); | 2996 | var pointers = std.ArrayList(bind.Pointer).init(self.base.allocator); |
| | 2997 | defer pointers.deinit(); |
| | 2998 | |
| | 2999 | if (self.got_section_index) |idx| { |
| | 3000 | const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| | 3001 | const sect = seg.sections.items[idx]; |
| | 3002 | const base_offset = sect.addr - seg.inner.vmaddr; |
| | 3003 | const segment_id = self.data_const_segment_cmd_index.?; |
| | 3004 | |
| | 3005 | for (self.offset_table.items) |entry| { |
| | 3006 | if (entry.kind == .Extern) continue; |
| | 3007 | try pointers.append(.{ |
| | 3008 | .offset = base_offset + entry.index * @sizeOf(u64), |
| | 3009 | .segment_id = segment_id, |
| | 3010 | }); |
| | 3011 | } |
| | 3012 | } |
| | 3013 | |
| | 3014 | if (self.la_symbol_ptr_section_index) |idx| { |
| | 3015 | try pointers.ensureCapacity(pointers.items.len + self.lazy_imports.items().len); |
| | 3016 | const seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| | 3017 | const sect = seg.sections.items[idx]; |
| | 3018 | const base_offset = sect.addr - seg.inner.vmaddr; |
| | 3019 | const segment_id = self.data_segment_cmd_index.?; |
| | 3020 | |
| | 3021 | for (self.lazy_imports.items()) |entry| { |
| | 3022 | pointers.appendAssumeCapacity(.{ |
| | 3023 | .offset = base_offset + entry.value.index * @sizeOf(u64), |
| | 3024 | .segment_id = segment_id, |
| | 3025 | }); |
| | 3026 | } |
| | 3027 | } |
| | 3028 | |
| | 3029 | std.sort.sort(bind.Pointer, pointers.items, {}, bind.pointerCmp); |
| | 3030 | |
| | 3031 | const size = try bind.rebaseInfoSize(pointers.items); |
| 2844 | var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size)); | 3032 | var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size)); |
| 2845 | defer self.base.allocator.free(buffer); | 3033 | defer self.base.allocator.free(buffer); |
| 2846 | | 3034 | |
| 2847 | var stream = std.io.fixedBufferStream(buffer); | 3035 | var stream = std.io.fixedBufferStream(buffer); |
| 2848 | try writeRebaseInfo(self.extern_lazy_symbols.items(), stream.writer()); | 3036 | try bind.writeRebaseInfo(pointers.items, stream.writer()); |
| 2849 | | 3037 | |
| 2850 | const linkedit_segment = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; | | |
| 2851 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; | 3038 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; |
| 2852 | const allocated_size = self.allocatedSizeLinkedit(dyld_info.rebase_off); | 3039 | const allocated_size = self.allocatedSizeLinkedit(dyld_info.rebase_off); |
| 2853 | const needed_size = mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64)); | 3040 | const needed_size = mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64)); |
| ... | @@ -2872,14 +3059,34 @@ fn writeBindingInfoTable(self: *MachO) !void { | ... | @@ -2872,14 +3059,34 @@ fn writeBindingInfoTable(self: *MachO) !void { |
| 2872 | const tracy = trace(@src()); | 3059 | const tracy = trace(@src()); |
| 2873 | defer tracy.end(); | 3060 | defer tracy.end(); |
| 2874 | | 3061 | |
| 2875 | const size = try bindInfoSize(self.extern_nonlazy_symbols.items()); | 3062 | var pointers = std.ArrayList(bind.Pointer).init(self.base.allocator); |
| | 3063 | defer pointers.deinit(); |
| | 3064 | |
| | 3065 | if (self.got_section_index) |idx| { |
| | 3066 | const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| | 3067 | const sect = seg.sections.items[idx]; |
| | 3068 | const base_offset = sect.addr - seg.inner.vmaddr; |
| | 3069 | const segment_id = @intCast(u16, self.data_const_segment_cmd_index.?); |
| | 3070 | |
| | 3071 | for (self.offset_table.items) |entry| { |
| | 3072 | if (entry.kind == .Local) continue; |
| | 3073 | const import = self.nonlazy_imports.items()[entry.symbol]; |
| | 3074 | try pointers.append(.{ |
| | 3075 | .offset = base_offset + entry.index * @sizeOf(u64), |
| | 3076 | .segment_id = segment_id, |
| | 3077 | .dylib_ordinal = import.value.dylib_ordinal, |
| | 3078 | .name = import.key, |
| | 3079 | }); |
| | 3080 | } |
| | 3081 | } |
| | 3082 | |
| | 3083 | const size = try bind.bindInfoSize(pointers.items); |
| 2876 | var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size)); | 3084 | var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size)); |
| 2877 | defer self.base.allocator.free(buffer); | 3085 | defer self.base.allocator.free(buffer); |
| 2878 | | 3086 | |
| 2879 | var stream = std.io.fixedBufferStream(buffer); | 3087 | var stream = std.io.fixedBufferStream(buffer); |
| 2880 | try writeBindInfo(self.extern_nonlazy_symbols.items(), stream.writer()); | 3088 | try bind.writeBindInfo(pointers.items, stream.writer()); |
| 2881 | | 3089 | |
| 2882 | const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; | | |
| 2883 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; | 3090 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; |
| 2884 | const allocated_size = self.allocatedSizeLinkedit(dyld_info.bind_off); | 3091 | const allocated_size = self.allocatedSizeLinkedit(dyld_info.bind_off); |
| 2885 | const needed_size = mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64)); | 3092 | const needed_size = mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64)); |
| ... | @@ -2901,14 +3108,36 @@ fn writeBindingInfoTable(self: *MachO) !void { | ... | @@ -2901,14 +3108,36 @@ fn writeBindingInfoTable(self: *MachO) !void { |
| 2901 | fn writeLazyBindingInfoTable(self: *MachO) !void { | 3108 | fn writeLazyBindingInfoTable(self: *MachO) !void { |
| 2902 | if (!self.lazy_binding_info_dirty) return; | 3109 | if (!self.lazy_binding_info_dirty) return; |
| 2903 | | 3110 | |
| 2904 | const size = try lazyBindInfoSize(self.extern_lazy_symbols.items()); | 3111 | const tracy = trace(@src()); |
| | 3112 | defer tracy.end(); |
| | 3113 | |
| | 3114 | var pointers = std.ArrayList(bind.Pointer).init(self.base.allocator); |
| | 3115 | defer pointers.deinit(); |
| | 3116 | |
| | 3117 | if (self.la_symbol_ptr_section_index) |idx| { |
| | 3118 | try pointers.ensureCapacity(self.lazy_imports.items().len); |
| | 3119 | const seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| | 3120 | const sect = seg.sections.items[idx]; |
| | 3121 | const base_offset = sect.addr - seg.inner.vmaddr; |
| | 3122 | const segment_id = @intCast(u16, self.data_segment_cmd_index.?); |
| | 3123 | |
| | 3124 | for (self.lazy_imports.items()) |entry| { |
| | 3125 | pointers.appendAssumeCapacity(.{ |
| | 3126 | .offset = base_offset + entry.value.index * @sizeOf(u64), |
| | 3127 | .segment_id = segment_id, |
| | 3128 | .dylib_ordinal = entry.value.dylib_ordinal, |
| | 3129 | .name = entry.key, |
| | 3130 | }); |
| | 3131 | } |
| | 3132 | } |
| | 3133 | |
| | 3134 | const size = try bind.lazyBindInfoSize(pointers.items); |
| 2905 | var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size)); | 3135 | var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size)); |
| 2906 | defer self.base.allocator.free(buffer); | 3136 | defer self.base.allocator.free(buffer); |
| 2907 | | 3137 | |
| 2908 | var stream = std.io.fixedBufferStream(buffer); | 3138 | var stream = std.io.fixedBufferStream(buffer); |
| 2909 | try writeLazyBindInfo(self.extern_lazy_symbols.items(), stream.writer()); | 3139 | try bind.writeLazyBindInfo(pointers.items, stream.writer()); |
| 2910 | | 3140 | |
| 2911 | const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; | | |
| 2912 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; | 3141 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; |
| 2913 | const allocated_size = self.allocatedSizeLinkedit(dyld_info.lazy_bind_off); | 3142 | const allocated_size = self.allocatedSizeLinkedit(dyld_info.lazy_bind_off); |
| 2914 | const needed_size = mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64)); | 3143 | const needed_size = mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64)); |
| ... | @@ -2929,7 +3158,7 @@ fn writeLazyBindingInfoTable(self: *MachO) !void { | ... | @@ -2929,7 +3158,7 @@ fn writeLazyBindingInfoTable(self: *MachO) !void { |
| 2929 | } | 3158 | } |
| 2930 | | 3159 | |
| 2931 | fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void { | 3160 | fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void { |
| 2932 | if (self.extern_lazy_symbols.items().len == 0) return; | 3161 | if (self.lazy_imports.items().len == 0) return; |
| 2933 | | 3162 | |
| 2934 | var stream = std.io.fixedBufferStream(buffer); | 3163 | var stream = std.io.fixedBufferStream(buffer); |
| 2935 | var reader = stream.reader(); | 3164 | var reader = stream.reader(); |
| ... | @@ -2975,7 +3204,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void { | ... | @@ -2975,7 +3204,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void { |
| 2975 | else => {}, | 3204 | else => {}, |
| 2976 | } | 3205 | } |
| 2977 | } | 3206 | } |
| 2978 | assert(self.extern_lazy_symbols.items().len <= offsets.items.len); | 3207 | assert(self.lazy_imports.items().len <= offsets.items.len); |
| 2979 | | 3208 | |
| 2980 | const stub_size: u4 = switch (self.base.options.target.cpu.arch) { | 3209 | const stub_size: u4 = switch (self.base.options.target.cpu.arch) { |
| 2981 | .x86_64 => 10, | 3210 | .x86_64 => 10, |
| ... | @@ -2988,7 +3217,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void { | ... | @@ -2988,7 +3217,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void { |
| 2988 | else => unreachable, | 3217 | else => unreachable, |
| 2989 | }; | 3218 | }; |
| 2990 | var buf: [@sizeOf(u32)]u8 = undefined; | 3219 | var buf: [@sizeOf(u32)]u8 = undefined; |
| 2991 | for (self.extern_lazy_symbols.items()) |_, i| { | 3220 | for (self.lazy_imports.items()) |_, i| { |
| 2992 | const placeholder_off = self.stub_helper_stubs_start_off.? + i * stub_size + off; | 3221 | const placeholder_off = self.stub_helper_stubs_start_off.? + i * stub_size + off; |
| 2993 | mem.writeIntLittle(u32, &buf, offsets.items[i]); | 3222 | mem.writeIntLittle(u32, &buf, offsets.items[i]); |
| 2994 | try self.base.file.?.pwriteAll(&buf, placeholder_off); | 3223 | try self.base.file.?.pwriteAll(&buf, placeholder_off); |
| ... | @@ -3193,12 +3422,12 @@ fn parseSymbolTable(self: *MachO) !void { | ... | @@ -3193,12 +3422,12 @@ fn parseSymbolTable(self: *MachO) !void { |
| 3193 | const nread = try self.base.file.?.preadAll(@ptrCast([*]u8, buffer)[0 .. symtab.nsyms * @sizeOf(macho.nlist_64)], symtab.symoff); | 3422 | const nread = try self.base.file.?.preadAll(@ptrCast([*]u8, buffer)[0 .. symtab.nsyms * @sizeOf(macho.nlist_64)], symtab.symoff); |
| 3194 | assert(@divExact(nread, @sizeOf(macho.nlist_64)) == buffer.len); | 3423 | assert(@divExact(nread, @sizeOf(macho.nlist_64)) == buffer.len); |
| 3195 | | 3424 | |
| 3196 | try self.local_symbols.ensureCapacity(self.base.allocator, dysymtab.nlocalsym); | 3425 | try self.locals.ensureCapacity(self.base.allocator, dysymtab.nlocalsym); |
| 3197 | try self.global_symbols.ensureCapacity(self.base.allocator, dysymtab.nextdefsym); | 3426 | try self.globals.ensureCapacity(self.base.allocator, dysymtab.nextdefsym); |
| 3198 | try self.undef_symbols.ensureCapacity(self.base.allocator, dysymtab.nundefsym); | 3427 | try self.undef_symbols.ensureCapacity(self.base.allocator, dysymtab.nundefsym); |
| 3199 | | 3428 | |
| 3200 | self.local_symbols.appendSliceAssumeCapacity(buffer[dysymtab.ilocalsym .. dysymtab.ilocalsym + dysymtab.nlocalsym]); | 3429 | self.locals.appendSliceAssumeCapacity(buffer[dysymtab.ilocalsym .. dysymtab.ilocalsym + dysymtab.nlocalsym]); |
| 3201 | self.global_symbols.appendSliceAssumeCapacity(buffer[dysymtab.iextdefsym .. dysymtab.iextdefsym + dysymtab.nextdefsym]); | 3430 | self.globals.appendSliceAssumeCapacity(buffer[dysymtab.iextdefsym .. dysymtab.iextdefsym + dysymtab.nextdefsym]); |
| 3202 | self.undef_symbols.appendSliceAssumeCapacity(buffer[dysymtab.iundefsym .. dysymtab.iundefsym + dysymtab.nundefsym]); | 3431 | self.undef_symbols.appendSliceAssumeCapacity(buffer[dysymtab.iundefsym .. dysymtab.iundefsym + dysymtab.nundefsym]); |
| 3203 | } | 3432 | } |
| 3204 | | 3433 | |