| ... | @@ -175,6 +175,22 @@ libsystem_cmd_dirty: bool = false, | ... | @@ -175,6 +175,22 @@ libsystem_cmd_dirty: bool = false, |
| 175 | text_block_free_list: std.ArrayListUnmanaged(*TextBlock) = .{}, | 175 | text_block_free_list: std.ArrayListUnmanaged(*TextBlock) = .{}, |
| 176 | /// Pointer to the last allocated text block | 176 | /// Pointer to the last allocated text block |
| 177 | last_text_block: ?*TextBlock = null, | 177 | last_text_block: ?*TextBlock = null, |
| | 178 | /// A list of all PIE fixups required for this run of the linker. |
| | 179 | /// Warning, this is currently NOT thread-safe. See the TODO below. |
| | 180 | /// TODO Move this list inside `updateDecl` where it should be allocated |
| | 181 | /// prior to calling `generateSymbol`, and then immediately deallocated |
| | 182 | /// rather than sitting in the global scope. |
| | 183 | pie_fixups: std.ArrayListUnmanaged(PieFixup) = .{}, |
| | 184 | |
| | 185 | pub const PieFixup = struct { |
| | 186 | /// Target address we wanted to address in absolute terms. |
| | 187 | address: u64, |
| | 188 | /// Where in the byte stream we should perform the fixup. |
| | 189 | start: usize, |
| | 190 | /// The length of the byte stream. For x86_64, this will be |
| | 191 | /// variable. For aarch64, it will be fixed at 4 bytes. |
| | 192 | len: usize, |
| | 193 | }; |
| 178 | | 194 | |
| 179 | /// `alloc_num / alloc_den` is the factor of padding when allocating. | 195 | /// `alloc_num / alloc_den` is the factor of padding when allocating. |
| 180 | const alloc_num = 4; | 196 | const alloc_num = 4; |
| ... | @@ -215,20 +231,10 @@ pub const TextBlock = struct { | ... | @@ -215,20 +231,10 @@ pub const TextBlock = struct { |
| 215 | /// Unlike in Elf, we need to store the size of this symbol as part of | 231 | /// Unlike in Elf, we need to store the size of this symbol as part of |
| 216 | /// the TextBlock since macho.nlist_64 lacks this information. | 232 | /// the TextBlock since macho.nlist_64 lacks this information. |
| 217 | size: u64, | 233 | size: u64, |
| 218 | /// List of PIE fixups in the code. | | |
| 219 | /// This is a table of all position-relative positions that will need fixups | | |
| 220 | /// after codegen when linker assigns addresses to GOT entries. | | |
| 221 | pie_fixups: std.ArrayListUnmanaged(PieFixup) = .{}, | | |
| 222 | /// Points to the previous and next neighbours | 234 | /// Points to the previous and next neighbours |
| 223 | prev: ?*TextBlock, | 235 | prev: ?*TextBlock, |
| 224 | next: ?*TextBlock, | 236 | next: ?*TextBlock, |
| 225 | | 237 | |
| 226 | pub const PieFixup = struct { | | |
| 227 | address: u64, | | |
| 228 | start: usize, | | |
| 229 | len: usize, | | |
| 230 | }; | | |
| 231 | | | |
| 232 | pub const empty = TextBlock{ | 238 | pub const empty = TextBlock{ |
| 233 | .local_sym_index = 0, | 239 | .local_sym_index = 0, |
| 234 | .offset_table_index = undefined, | 240 | .offset_table_index = undefined, |
| ... | @@ -237,14 +243,6 @@ pub const TextBlock = struct { | ... | @@ -237,14 +243,6 @@ pub const TextBlock = struct { |
| 237 | .next = null, | 243 | .next = null, |
| 238 | }; | 244 | }; |
| 239 | | 245 | |
| 240 | pub fn addPieFixup(self: *TextBlock, alloc: *Allocator, fixup: PieFixup) !void { | | |
| 241 | return self.pie_fixups.append(alloc, fixup); | | |
| 242 | } | | |
| 243 | | | |
| 244 | fn deinit(self: *TextBlock, alloc: *Allocator) void { | | |
| 245 | self.pie_fixups.deinit(alloc); | | |
| 246 | } | | |
| 247 | | | |
| 248 | /// Returns how much room there is to grow in virtual address space. | 246 | /// Returns how much room there is to grow in virtual address space. |
| 249 | /// File offset relocation happens transparently, so it is not included in | 247 | /// File offset relocation happens transparently, so it is not included in |
| 250 | /// this calculation. | 248 | /// this calculation. |
| ... | @@ -849,9 +847,7 @@ fn darwinArchString(arch: std.Target.Cpu.Arch) []const u8 { | ... | @@ -849,9 +847,7 @@ fn darwinArchString(arch: std.Target.Cpu.Arch) []const u8 { |
| 849 | } | 847 | } |
| 850 | | 848 | |
| 851 | pub fn deinit(self: *MachO) void { | 849 | pub fn deinit(self: *MachO) void { |
| 852 | for (self.text_block_free_list.items) |tb| { | 850 | self.pie_fixups.deinit(self.base.allocator); |
| 853 | tb.deinit(self.base.allocator); | | |
| 854 | } | | |
| 855 | self.text_block_free_list.deinit(self.base.allocator); | 851 | self.text_block_free_list.deinit(self.base.allocator); |
| 856 | self.offset_table.deinit(self.base.allocator); | 852 | self.offset_table.deinit(self.base.allocator); |
| 857 | self.offset_table_free_list.deinit(self.base.allocator); | 853 | self.offset_table_free_list.deinit(self.base.allocator); |
| ... | @@ -894,9 +890,7 @@ fn freeTextBlock(self: *MachO, text_block: *TextBlock) void { | ... | @@ -894,9 +890,7 @@ fn freeTextBlock(self: *MachO, text_block: *TextBlock) void { |
| 894 | if (!already_have_free_list_node and prev.freeListEligible(self.*)) { | 890 | if (!already_have_free_list_node and prev.freeListEligible(self.*)) { |
| 895 | // The free list is heuristics, it doesn't have to be perfect, so we can ignore | 891 | // The free list is heuristics, it doesn't have to be perfect, so we can ignore |
| 896 | // the OOM here. | 892 | // the OOM here. |
| 897 | self.text_block_free_list.append(self.base.allocator, prev) catch { | 893 | self.text_block_free_list.append(self.base.allocator, prev) catch {}; |
| 898 | prev.deinit(self.base.allocator); | | |
| 899 | }; | | |
| 900 | } | 894 | } |
| 901 | } else { | 895 | } else { |
| 902 | text_block.prev = null; | 896 | text_block.prev = null; |
| ... | @@ -1018,7 +1012,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { | ... | @@ -1018,7 +1012,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 1018 | | 1012 | |
| 1019 | // Perform PIE fixups (if any) | 1013 | // Perform PIE fixups (if any) |
| 1020 | const got_section = self.sections.items[self.got_section_index.?]; | 1014 | const got_section = self.sections.items[self.got_section_index.?]; |
| 1021 | while (decl.link.macho.pie_fixups.popOrNull()) |fixup| { | 1015 | while (self.pie_fixups.popOrNull()) |fixup| { |
| 1022 | const target_addr = fixup.address; | 1016 | const target_addr = fixup.address; |
| 1023 | const this_addr = symbol.n_value + fixup.start; | 1017 | const this_addr = symbol.n_value + fixup.start; |
| 1024 | if (self.base.options.target.cpu.arch == .x86_64) { | 1018 | if (self.base.options.target.cpu.arch == .x86_64) { |
| ... | @@ -1761,7 +1755,7 @@ fn writeCodeSignature(self: *MachO) !void { | ... | @@ -1761,7 +1755,7 @@ fn writeCodeSignature(self: *MachO) !void { |
| 1761 | } | 1755 | } |
| 1762 | | 1756 | |
| 1763 | fn writeExportTrie(self: *MachO) !void { | 1757 | fn writeExportTrie(self: *MachO) !void { |
| 1764 | assert(self.global_symbols.items.len > 0); | 1758 | if (self.global_symbols.items.len == 0) return; |
| 1765 | | 1759 | |
| 1766 | var trie: Trie = .{}; | 1760 | var trie: Trie = .{}; |
| 1767 | defer trie.deinit(self.base.allocator); | 1761 | defer trie.deinit(self.base.allocator); |