| author | |
| committer | |
| log | 555b66c25567ab23402e3792bdbe81b7a4e98803 |
| tree | 7f4dab9ab3c66caf1c4057b46d5dc068f1104bbc |
| parent | dbd2eb7c7f9267e8ae508d0995c1d4c5a3b46309 |
4 files changed, 111 insertions(+), 152 deletions(-)
src/link/MachO/Object.zig+39-19| ... | @@ -339,6 +339,7 @@ const TextBlockParser = struct { | ... | @@ -339,6 +339,7 @@ const TextBlockParser = struct { |
| 339 | zld: *Zld, | 339 | zld: *Zld, |
| 340 | nlists: []NlistWithIndex, | 340 | nlists: []NlistWithIndex, |
| 341 | index: u32 = 0, | 341 | index: u32 = 0, |
| 342 | match: Zld.MatchingSection, | ||
| 342 | 343 | ||
| 343 | fn peek(self: *TextBlockParser) ?NlistWithIndex { | 344 | fn peek(self: *TextBlockParser) ?NlistWithIndex { |
| 344 | return if (self.index + 1 < self.nlists.len) self.nlists[self.index + 1] else null; | 345 | return if (self.index + 1 < self.nlists.len) self.nlists[self.index + 1] else null; |
| ... | @@ -405,6 +406,8 @@ const TextBlockParser = struct { | ... | @@ -405,6 +406,8 @@ const TextBlockParser = struct { |
| 405 | const senior_nlist = aliases.pop(); | 406 | const senior_nlist = aliases.pop(); |
| 406 | const senior_sym = self.zld.locals.items[senior_nlist.index]; | 407 | const senior_sym = self.zld.locals.items[senior_nlist.index]; |
| 407 | assert(senior_sym.payload == .regular); | 408 | assert(senior_sym.payload == .regular); |
| 409 | senior_sym.payload.regular.segment_id = self.match.seg; | ||
| 410 | senior_sym.payload.regular.section_id = self.match.sect; | ||
| 408 | 411 | ||
| 409 | const start_addr = senior_nlist.nlist.n_value - self.section.addr; | 412 | const start_addr = senior_nlist.nlist.n_value - self.section.addr; |
| 410 | const end_addr = if (next_nlist) |n| n.nlist.n_value - self.section.addr else self.section.size; | 413 | const end_addr = if (next_nlist) |n| n.nlist.n_value - self.section.addr else self.section.size; |
| ... | @@ -417,6 +420,11 @@ const TextBlockParser = struct { | ... | @@ -417,6 +420,11 @@ const TextBlockParser = struct { |
| 417 | try out.ensureTotalCapacity(aliases.items.len); | 420 | try out.ensureTotalCapacity(aliases.items.len); |
| 418 | for (aliases.items) |alias| { | 421 | for (aliases.items) |alias| { |
| 419 | out.appendAssumeCapacity(alias.index); | 422 | out.appendAssumeCapacity(alias.index); |
| 423 | |||
| 424 | const sym = self.zld.locals.items[alias.index]; | ||
| 425 | const reg = &sym.payload.regular; | ||
| 426 | reg.segment_id = self.match.seg; | ||
| 427 | reg.section_id = self.match.sect; | ||
| 420 | } | 428 | } |
| 421 | break :blk out.toOwnedSlice(); | 429 | break :blk out.toOwnedSlice(); |
| 422 | } else null; | 430 | } else null; |
| ... | @@ -439,6 +447,18 @@ const TextBlockParser = struct { | ... | @@ -439,6 +447,18 @@ const TextBlockParser = struct { |
| 439 | try self.object.parseRelocs(self.zld, relocs, block, start_addr); | 447 | try self.object.parseRelocs(self.zld, relocs, block, start_addr); |
| 440 | } | 448 | } |
| 441 | 449 | ||
| 450 | const is_zerofill = blk: { | ||
| 451 | const tseg = self.zld.load_commands.items[self.match.seg].Segment; | ||
| 452 | const tsect = tseg.sections.items[self.match.sect]; | ||
| 453 | const tsect_type = sectionType(tsect); | ||
| 454 | break :blk tsect_type == macho.S_ZEROFILL or | ||
| 455 | tsect_type == macho.S_THREAD_LOCAL_ZEROFILL or | ||
| 456 | tsect_type == macho.S_THREAD_LOCAL_VARIABLES; | ||
| 457 | }; | ||
| 458 | if (is_zerofill) { | ||
| 459 | mem.set(u8, block.code, 0); | ||
| 460 | } | ||
| 461 | |||
| 442 | self.index += 1; | 462 | self.index += 1; |
| 443 | 463 | ||
| 444 | return block; | 464 | return block; |
| ... | @@ -511,28 +531,16 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { | ... | @@ -511,28 +531,16 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { |
| 511 | .object = self, | 531 | .object = self, |
| 512 | .zld = zld, | 532 | .zld = zld, |
| 513 | .nlists = filtered_nlists, | 533 | .nlists = filtered_nlists, |
| 534 | .match = match, | ||
| 514 | }; | 535 | }; |
| 515 | 536 | ||
| 516 | while (try parser.next()) |block| { | 537 | while (try parser.next()) |block| { |
| 517 | { | 538 | const sym = zld.locals.items[block.local_sym_index]; |
| 518 | const sym = zld.locals.items[block.local_sym_index]; | 539 | const reg = &sym.payload.regular; |
| 519 | const reg = &sym.payload.regular; | 540 | if (reg.file) |file| { |
| 520 | if (reg.file) |file| { | 541 | if (file != self) { |
| 521 | if (file != self) { | 542 | log.warn("deduping definition of {s} in {s}", .{ sym.name, self.name.? }); |
| 522 | log.warn("deduping definition of {s} in {s}", .{ sym.name, self.name.? }); | 543 | continue; |
| 523 | continue; | ||
| 524 | } | ||
| 525 | } | ||
| 526 | reg.segment_id = match.seg; | ||
| 527 | reg.section_id = match.sect; | ||
| 528 | } | ||
| 529 | |||
| 530 | if (block.aliases) |aliases| { | ||
| 531 | for (aliases) |alias| { | ||
| 532 | const sym = zld.locals.items[alias]; | ||
| 533 | const reg = &sym.payload.regular; | ||
| 534 | reg.segment_id = match.seg; | ||
| 535 | reg.section_id = match.sect; | ||
| 536 | } | 544 | } |
| 537 | } | 545 | } |
| 538 | 546 | ||
| ... | @@ -587,6 +595,18 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { | ... | @@ -587,6 +595,18 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { |
| 587 | try self.parseRelocs(zld, relocs, block, 0); | 595 | try self.parseRelocs(zld, relocs, block, 0); |
| 588 | } | 596 | } |
| 589 | 597 | ||
| 598 | const is_zerofill = blk: { | ||
| 599 | const tseg = zld.load_commands.items[match.seg].Segment; | ||
| 600 | const tsect = tseg.sections.items[match.sect]; | ||
| 601 | const tsect_type = sectionType(tsect); | ||
| 602 | break :blk tsect_type == macho.S_ZEROFILL or | ||
| 603 | tsect_type == macho.S_THREAD_LOCAL_ZEROFILL or | ||
| 604 | tsect_type == macho.S_THREAD_LOCAL_VARIABLES; | ||
| 605 | }; | ||
| 606 | if (is_zerofill) { | ||
| 607 | mem.set(u8, block.code, 0); | ||
| 608 | } | ||
| 609 | |||
| 590 | if (zld.last_text_block) |last| { | 610 | if (zld.last_text_block) |last| { |
| 591 | last.next = block; | 611 | last.next = block; |
| 592 | block.prev = last; | 612 | block.prev = last; |
src/link/MachO/Symbol.zig+19-2| ... | @@ -2,6 +2,7 @@ const Symbol = @This(); | ... | @@ -2,6 +2,7 @@ const Symbol = @This(); |
| 2 | 2 | ||
| 3 | const std = @import("std"); | 3 | const std = @import("std"); |
| 4 | const assert = std.debug.assert; | 4 | const assert = std.debug.assert; |
| 5 | const commands = @import("commands.zig"); | ||
| 5 | const macho = std.macho; | 6 | const macho = std.macho; |
| 6 | const mem = std.mem; | 7 | const mem = std.mem; |
| 7 | 8 | ||
| ... | @@ -57,6 +58,8 @@ pub const Regular = struct { | ... | @@ -57,6 +58,8 @@ pub const Regular = struct { |
| 57 | 58 | ||
| 58 | local_sym_index: u32 = 0, | 59 | local_sym_index: u32 = 0, |
| 59 | 60 | ||
| 61 | should_rebase: bool = false, | ||
| 62 | |||
| 60 | pub const Linkage = enum { | 63 | pub const Linkage = enum { |
| 61 | translation_unit, | 64 | translation_unit, |
| 62 | linkage_unit, | 65 | linkage_unit, |
| ... | @@ -74,6 +77,9 @@ pub const Regular = struct { | ... | @@ -74,6 +77,9 @@ pub const Regular = struct { |
| 74 | if (self.weak_ref) { | 77 | if (self.weak_ref) { |
| 75 | try std.fmt.format(writer, ".weak_ref, ", .{}); | 78 | try std.fmt.format(writer, ".weak_ref, ", .{}); |
| 76 | } | 79 | } |
| 80 | if (self.should_rebase) { | ||
| 81 | try std.fmt.format(writer, ".should_rebase, ", .{}); | ||
| 82 | } | ||
| 77 | if (self.file) |file| { | 83 | if (self.file) |file| { |
| 78 | try std.fmt.format(writer, ".file = {s}, ", .{file.name.?}); | 84 | try std.fmt.format(writer, ".file = {s}, ", .{file.name.?}); |
| 79 | } | 85 | } |
| ... | @@ -108,8 +114,8 @@ pub const Proxy = struct { | ... | @@ -108,8 +114,8 @@ pub const Proxy = struct { |
| 108 | /// Dynamic binding info - spots within the final | 114 | /// Dynamic binding info - spots within the final |
| 109 | /// executable where this proxy is referenced from. | 115 | /// executable where this proxy is referenced from. |
| 110 | bind_info: std.ArrayListUnmanaged(struct { | 116 | bind_info: std.ArrayListUnmanaged(struct { |
| 111 | segment_id: u16, | 117 | local_sym_index: u32, |
| 112 | address: u64, | 118 | offset: u32, |
| 113 | }) = .{}, | 119 | }) = .{}, |
| 114 | 120 | ||
| 115 | /// Dylib where to locate this symbol. | 121 | /// Dylib where to locate this symbol. |
| ... | @@ -198,6 +204,17 @@ pub fn isTemp(symbol: Symbol) bool { | ... | @@ -198,6 +204,17 @@ pub fn isTemp(symbol: Symbol) bool { |
| 198 | return false; | 204 | return false; |
| 199 | } | 205 | } |
| 200 | 206 | ||
| 207 | pub fn needsTlvOffset(self: Symbol, zld: *Zld) bool { | ||
| 208 | if (self.payload != .regular) return false; | ||
| 209 | |||
| 210 | const reg = self.payload.regular; | ||
| 211 | const seg = zld.load_command.items[reg.segment_id].Segment; | ||
| 212 | const sect = seg.sections.items[reg.section_id]; | ||
| 213 | const sect_type = commands.sectionType(sect); | ||
| 214 | |||
| 215 | return sect_type == macho.S_THREAD_LOCAL_VARIABLES; | ||
| 216 | } | ||
| 217 | |||
| 201 | pub fn asNlist(symbol: *Symbol, strtab: *StringTable) !macho.nlist_64 { | 218 | pub fn asNlist(symbol: *Symbol, strtab: *StringTable) !macho.nlist_64 { |
| 202 | const n_strx = try strtab.getOrPut(symbol.name); | 219 | const n_strx = try strtab.getOrPut(symbol.name); |
| 203 | const nlist = nlist: { | 220 | const nlist = nlist: { |
src/link/MachO/Zld.zig+2-127| ... | @@ -107,8 +107,6 @@ locals: std.ArrayListUnmanaged(*Symbol) = .{}, | ... | @@ -107,8 +107,6 @@ locals: std.ArrayListUnmanaged(*Symbol) = .{}, |
| 107 | imports: std.ArrayListUnmanaged(*Symbol) = .{}, | 107 | imports: std.ArrayListUnmanaged(*Symbol) = .{}, |
| 108 | globals: std.StringArrayHashMapUnmanaged(*Symbol) = .{}, | 108 | globals: std.StringArrayHashMapUnmanaged(*Symbol) = .{}, |
| 109 | 109 | ||
| 110 | threadlocal_offsets: std.ArrayListUnmanaged(TlvOffset) = .{}, // TODO merge with Symbol abstraction | ||
| 111 | local_rebases: std.ArrayListUnmanaged(Pointer) = .{}, | ||
| 112 | stubs: std.ArrayListUnmanaged(*Symbol) = .{}, | 110 | stubs: std.ArrayListUnmanaged(*Symbol) = .{}, |
| 113 | got_entries: std.ArrayListUnmanaged(*Symbol) = .{}, | 111 | got_entries: std.ArrayListUnmanaged(*Symbol) = .{}, |
| 114 | 112 | ||
| ... | @@ -197,8 +195,6 @@ pub fn init(allocator: *Allocator) !Zld { | ... | @@ -197,8 +195,6 @@ pub fn init(allocator: *Allocator) !Zld { |
| 197 | } | 195 | } |
| 198 | 196 | ||
| 199 | pub fn deinit(self: *Zld) void { | 197 | pub fn deinit(self: *Zld) void { |
| 200 | self.threadlocal_offsets.deinit(self.allocator); | ||
| 201 | self.local_rebases.deinit(self.allocator); | ||
| 202 | self.stubs.deinit(self.allocator); | 198 | self.stubs.deinit(self.allocator); |
| 203 | self.got_entries.deinit(self.allocator); | 199 | self.got_entries.deinit(self.allocator); |
| 204 | 200 | ||
| ... | @@ -225,8 +221,6 @@ pub fn deinit(self: *Zld) void { | ... | @@ -225,8 +221,6 @@ pub fn deinit(self: *Zld) void { |
| 225 | } | 221 | } |
| 226 | self.dylibs.deinit(self.allocator); | 222 | self.dylibs.deinit(self.allocator); |
| 227 | 223 | ||
| 228 | self.globals.deinit(self.allocator); | ||
| 229 | |||
| 230 | for (self.imports.items) |sym| { | 224 | for (self.imports.items) |sym| { |
| 231 | sym.deinit(self.allocator); | 225 | sym.deinit(self.allocator); |
| 232 | self.allocator.destroy(sym); | 226 | self.allocator.destroy(sym); |
| ... | @@ -239,6 +233,7 @@ pub fn deinit(self: *Zld) void { | ... | @@ -239,6 +233,7 @@ pub fn deinit(self: *Zld) void { |
| 239 | } | 233 | } |
| 240 | self.locals.deinit(self.allocator); | 234 | self.locals.deinit(self.allocator); |
| 241 | 235 | ||
| 236 | self.globals.deinit(self.allocator); | ||
| 242 | self.strtab.deinit(); | 237 | self.strtab.deinit(); |
| 243 | } | 238 | } |
| 244 | 239 | ||
| ... | @@ -290,7 +285,6 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg | ... | @@ -290,7 +285,6 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg |
| 290 | // try self.allocateDataSegment(); | 285 | // try self.allocateDataSegment(); |
| 291 | // self.allocateLinkeditSegment(); | 286 | // self.allocateLinkeditSegment(); |
| 292 | // try self.allocateSymbols(); | 287 | // try self.allocateSymbols(); |
| 293 | // try self.allocateProxyBindAddresses(); | ||
| 294 | // try self.flush(); | 288 | // try self.flush(); |
| 295 | } | 289 | } |
| 296 | 290 | ||
| ... | @@ -449,7 +443,7 @@ fn updateMetadata(self: *Zld) !void { | ... | @@ -449,7 +443,7 @@ fn updateMetadata(self: *Zld) !void { |
| 449 | } | 443 | } |
| 450 | } | 444 | } |
| 451 | 445 | ||
| 452 | const MatchingSection = struct { | 446 | pub const MatchingSection = struct { |
| 453 | seg: u16, | 447 | seg: u16, |
| 454 | sect: u16, | 448 | sect: u16, |
| 455 | }; | 449 | }; |
| ... | @@ -1140,31 +1134,6 @@ fn allocateSymbols(self: *Zld) !void { | ... | @@ -1140,31 +1134,6 @@ fn allocateSymbols(self: *Zld) !void { |
| 1140 | } | 1134 | } |
| 1141 | } | 1135 | } |
| 1142 | 1136 | ||
| 1143 | fn allocateProxyBindAddresses(self: *Zld) !void { | ||
| 1144 | for (self.objects.items) |object| { | ||
| 1145 | for (object.sections.items) |sect| { | ||
| 1146 | const relocs = sect.relocs orelse continue; | ||
| 1147 | |||
| 1148 | for (relocs) |rel| { | ||
| 1149 | if (rel.@"type" != .unsigned) continue; // GOT is currently special-cased | ||
| 1150 | if (rel.target != .symbol) continue; | ||
| 1151 | |||
| 1152 | const sym = object.symbols.items[rel.target.symbol]; | ||
| 1153 | if (sym.payload != .proxy) continue; | ||
| 1154 | |||
| 1155 | const target_map = sect.target_map orelse continue; | ||
| 1156 | const target_seg = self.load_commands.items[target_map.segment_id].Segment; | ||
| 1157 | const target_sect = target_seg.sections.items[target_map.section_id]; | ||
| 1158 | |||
| 1159 | try sym.payload.proxy.bind_info.append(self.allocator, .{ | ||
| 1160 | .segment_id = target_map.segment_id, | ||
| 1161 | .address = target_sect.addr + target_map.offset + rel.offset, | ||
| 1162 | }); | ||
| 1163 | } | ||
| 1164 | } | ||
| 1165 | } | ||
| 1166 | } | ||
| 1167 | |||
| 1168 | fn writeStubHelperCommon(self: *Zld) !void { | 1137 | fn writeStubHelperCommon(self: *Zld) !void { |
| 1169 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 1138 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 1170 | const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?]; | 1139 | const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?]; |
| ... | @@ -1748,72 +1717,6 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { | ... | @@ -1748,72 +1717,6 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { |
| 1748 | args.source_source_sect_addr = sect.inner.addr; | 1717 | args.source_source_sect_addr = sect.inner.addr; |
| 1749 | args.source_target_sect_addr = source_sect.inner.addr; | 1718 | args.source_target_sect_addr = source_sect.inner.addr; |
| 1750 | } | 1719 | } |
| 1751 | |||
| 1752 | const sect_type = sectionType(target_sect); | ||
| 1753 | const should_rebase = rebase: { | ||
| 1754 | if (!unsigned.is_64bit) break :rebase false; | ||
| 1755 | |||
| 1756 | // TODO actually, a check similar to what dyld is doing, that is, verifying | ||
| 1757 | // that the segment is writable should be enough here. | ||
| 1758 | const is_right_segment = blk: { | ||
| 1759 | if (self.data_segment_cmd_index) |idx| { | ||
| 1760 | if (target_map.segment_id == idx) { | ||
| 1761 | break :blk true; | ||
| 1762 | } | ||
| 1763 | } | ||
| 1764 | if (self.data_const_segment_cmd_index) |idx| { | ||
| 1765 | if (target_map.segment_id == idx) { | ||
| 1766 | break :blk true; | ||
| 1767 | } | ||
| 1768 | } | ||
| 1769 | break :blk false; | ||
| 1770 | }; | ||
| 1771 | |||
| 1772 | if (!is_right_segment) break :rebase false; | ||
| 1773 | if (sect_type != macho.S_LITERAL_POINTERS and | ||
| 1774 | sect_type != macho.S_REGULAR) | ||
| 1775 | { | ||
| 1776 | break :rebase false; | ||
| 1777 | } | ||
| 1778 | if (rel.target == .symbol) { | ||
| 1779 | const sym = object.symbols.items[rel.target.symbol]; | ||
| 1780 | if (sym.payload == .proxy) { | ||
| 1781 | break :rebase false; | ||
| 1782 | } | ||
| 1783 | } | ||
| 1784 | |||
| 1785 | break :rebase true; | ||
| 1786 | }; | ||
| 1787 | |||
| 1788 | if (should_rebase) { | ||
| 1789 | try self.local_rebases.append(self.allocator, .{ | ||
| 1790 | .offset = source_addr - target_seg.inner.vmaddr, | ||
| 1791 | .segment_id = target_map.segment_id, | ||
| 1792 | }); | ||
| 1793 | } | ||
| 1794 | |||
| 1795 | // TLV is handled via a separate offset mechanism. | ||
| 1796 | // Calculate the offset to the initializer. | ||
| 1797 | if (sect_type == macho.S_THREAD_LOCAL_VARIABLES) tlv: { | ||
| 1798 | // TODO we don't want to save offset to tlv_bootstrap | ||
| 1799 | if (mem.eql(u8, object.symbols.items[rel.target.symbol].name, "__tlv_bootstrap")) break :tlv; | ||
| 1800 | |||
| 1801 | const base_addr = blk: { | ||
| 1802 | if (self.tlv_data_section_index) |index| { | ||
| 1803 | const tlv_data = target_seg.sections.items[index]; | ||
| 1804 | break :blk tlv_data.addr; | ||
| 1805 | } else { | ||
| 1806 | const tlv_bss = target_seg.sections.items[self.tlv_bss_section_index.?]; | ||
| 1807 | break :blk tlv_bss.addr; | ||
| 1808 | } | ||
| 1809 | }; | ||
| 1810 | // Since we require TLV data to always preceed TLV bss section, we calculate | ||
| 1811 | // offsets wrt to the former if it is defined; otherwise, wrt to the latter. | ||
| 1812 | try self.threadlocal_offsets.append(self.allocator, .{ | ||
| 1813 | .source_addr = args.source_addr, | ||
| 1814 | .offset = args.target_addr - base_addr, | ||
| 1815 | }); | ||
| 1816 | } | ||
| 1817 | }, | 1720 | }, |
| 1818 | .got_page, .got_page_off, .got_load, .got, .pointer_to_got => { | 1721 | .got_page, .got_page_off, .got_load, .got, .pointer_to_got => { |
| 1819 | const dc_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; | 1722 | const dc_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| ... | @@ -1839,34 +1742,6 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { | ... | @@ -1839,34 +1742,6 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { |
| 1839 | try rel.resolve(args); | 1742 | try rel.resolve(args); |
| 1840 | } | 1743 | } |
| 1841 | } | 1744 | } |
| 1842 | |||
| 1843 | log.debug("writing contents of '{s},{s}' section from '{s}' from 0x{x} to 0x{x}", .{ | ||
| 1844 | segname, | ||
| 1845 | sectname, | ||
| 1846 | object.name, | ||
| 1847 | target_sect_off, | ||
| 1848 | target_sect_off + sect.code.len, | ||
| 1849 | }); | ||
| 1850 | |||
| 1851 | if (sectionType(target_sect) == macho.S_ZEROFILL or | ||
| 1852 | sectionType(target_sect) == macho.S_THREAD_LOCAL_ZEROFILL or | ||
| 1853 | sectionType(target_sect) == macho.S_THREAD_LOCAL_VARIABLES) | ||
| 1854 | { | ||
| 1855 | log.debug("zeroing out '{s},{s}' from 0x{x} to 0x{x}", .{ | ||
| 1856 | segmentName(target_sect), | ||
| 1857 | sectionName(target_sect), | ||
| 1858 | target_sect_off, | ||
| 1859 | target_sect_off + sect.code.len, | ||
| 1860 | }); | ||
| 1861 | |||
| 1862 | // Zero-out the space | ||
| 1863 | var zeroes = try self.allocator.alloc(u8, sect.code.len); | ||
| 1864 | defer self.allocator.free(zeroes); | ||
| 1865 | mem.set(u8, zeroes, 0); | ||
| 1866 | try self.file.?.pwriteAll(zeroes, target_sect_off); | ||
| 1867 | } else { | ||
| 1868 | try self.file.?.pwriteAll(sect.code, target_sect_off); | ||
| 1869 | } | ||
| 1870 | } | 1745 | } |
| 1871 | } | 1746 | } |
| 1872 | } | 1747 | } |
src/link/MachO/reloc.zig+51-4| ... | @@ -1,6 +1,7 @@ | ... | @@ -1,6 +1,7 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const aarch64 = @import("../../codegen/aarch64.zig"); | 2 | const aarch64 = @import("../../codegen/aarch64.zig"); |
| 3 | const assert = std.debug.assert; | 3 | const assert = std.debug.assert; |
| 4 | const commands = @import("commands.zig"); | ||
| 4 | const log = std.log.scoped(.reloc); | 5 | const log = std.log.scoped(.reloc); |
| 5 | const macho = std.macho; | 6 | const macho = std.macho; |
| 6 | const math = std.math; | 7 | const math = std.math; |
| ... | @@ -567,14 +568,60 @@ pub const Parser = struct { | ... | @@ -567,14 +568,60 @@ pub const Parser = struct { |
| 567 | const index = @intCast(u32, self.zld.got_entries.items.len); | 568 | const index = @intCast(u32, self.zld.got_entries.items.len); |
| 568 | out_rel.target.got_index = index; | 569 | out_rel.target.got_index = index; |
| 569 | try self.zld.got_entries.append(self.zld.allocator, out_rel.target); | 570 | try self.zld.got_entries.append(self.zld.allocator, out_rel.target); |
| 571 | |||
| 570 | log.debug("adding GOT entry for symbol {s} at index {}", .{ out_rel.target.name, index }); | 572 | log.debug("adding GOT entry for symbol {s} at index {}", .{ out_rel.target.name, index }); |
| 571 | } | 573 | } else if (out_rel.payload == .unsigned) { |
| 574 | const sym = out_rel.target; | ||
| 575 | switch (sym.payload) { | ||
| 576 | .proxy => { | ||
| 577 | try sym.payload.proxy.bind_info.append(self.zld.allocator, .{ | ||
| 578 | .local_sym_index = self.block.local_sym_index, | ||
| 579 | .offset = out_rel.offset, | ||
| 580 | }); | ||
| 581 | }, | ||
| 582 | else => { | ||
| 583 | const source_sym = self.zld.locals.items[self.block.local_sym_index]; | ||
| 584 | const source_reg = &source_sym.payload.regular; | ||
| 585 | const seg = self.zld.load_commands.items[source_reg.segment_id].Segment; | ||
| 586 | const sect = seg.sections.items[source_reg.section_id]; | ||
| 587 | const sect_type = commands.sectionType(sect); | ||
| 588 | |||
| 589 | const should_rebase = rebase: { | ||
| 590 | if (!out_rel.payload.unsigned.is_64bit) break :rebase false; | ||
| 591 | |||
| 592 | // TODO actually, a check similar to what dyld is doing, that is, verifying | ||
| 593 | // that the segment is writable should be enough here. | ||
| 594 | const is_right_segment = blk: { | ||
| 595 | if (self.zld.data_segment_cmd_index) |idx| { | ||
| 596 | if (source_reg.segment_id == idx) { | ||
| 597 | break :blk true; | ||
| 598 | } | ||
| 599 | } | ||
| 600 | if (self.zld.data_const_segment_cmd_index) |idx| { | ||
| 601 | if (source_reg.segment_id == idx) { | ||
| 602 | break :blk true; | ||
| 603 | } | ||
| 604 | } | ||
| 605 | break :blk false; | ||
| 606 | }; | ||
| 607 | |||
| 608 | if (!is_right_segment) break :rebase false; | ||
| 609 | if (sect_type != macho.S_LITERAL_POINTERS and | ||
| 610 | sect_type != macho.S_REGULAR) | ||
| 611 | { | ||
| 612 | break :rebase false; | ||
| 613 | } | ||
| 572 | 614 | ||
| 573 | if (out_rel.payload == .branch) { | 615 | break :rebase true; |
| 616 | }; | ||
| 617 | source_reg.should_rebase = should_rebase; | ||
| 618 | }, | ||
| 619 | } | ||
| 620 | } else if (out_rel.payload == .branch) blk: { | ||
| 574 | const sym = out_rel.target; | 621 | const sym = out_rel.target; |
| 575 | 622 | ||
| 576 | if (sym.stubs_index != null) continue; | 623 | if (sym.stubs_index != null) break :blk; |
| 577 | if (sym.payload != .proxy) continue; | 624 | if (sym.payload != .proxy) break :blk; |
| 578 | 625 | ||
| 579 | const index = @intCast(u32, self.zld.stubs.items.len); | 626 | const index = @intCast(u32, self.zld.stubs.items.len); |
| 580 | sym.stubs_index = index; | 627 | sym.stubs_index = index; |