authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-04-26 12:32:03+02:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-04-26 19:08:38-04:00
logbc69d5a00fb197a7bafc716b84c8675382074c19
tree45e7ace6d315054ffa1b45cbcd936d4427fa5428
parentb5b0b55582a3a8e3a3a7ba7bca4198d8779578f2

macho: invalidate GOT/stub relocs after segment shift in memory


3 files changed, 53 insertions(+), 26 deletions(-)

src/link/MachO.zig+26-8
...@@ -1146,7 +1146,9 @@ pub fn writeAtom(self: *MachO, atom_index: Atom.Index, code: []u8) !void {...@@ -1146,7 +1146,9 @@ pub fn writeAtom(self: *MachO, atom_index: Atom.Index, code: []u8) !void {
1146 if (self.relocs.getPtr(atom_index)) |rels| {1146 if (self.relocs.getPtr(atom_index)) |rels| {
1147 try relocs.ensureTotalCapacityPrecise(rels.items.len);1147 try relocs.ensureTotalCapacityPrecise(rels.items.len);
1148 for (rels.items) |*reloc| {1148 for (rels.items) |*reloc| {
1149 if (reloc.isResolvable(self)) relocs.appendAssumeCapacity(reloc);1149 if (reloc.isResolvable(self) and reloc.dirty) {
1150 relocs.appendAssumeCapacity(reloc);
1151 }
1150 }1152 }
1151 }1153 }
11521154
...@@ -1332,18 +1334,33 @@ fn markRelocsDirtyByTarget(self: *MachO, target: SymbolWithLoc) void {...@@ -1332,18 +1334,33 @@ fn markRelocsDirtyByTarget(self: *MachO, target: SymbolWithLoc) void {
13321334
1333fn markRelocsDirtyByAddress(self: *MachO, addr: u64) void {1335fn markRelocsDirtyByAddress(self: *MachO, addr: u64) void {
1334 log.debug("marking relocs dirty by address: {x}", .{addr});1336 log.debug("marking relocs dirty by address: {x}", .{addr});
1337
1338 const got_moved = blk: {
1339 const sect_id = self.got_section_index orelse break :blk false;
1340 break :blk self.sections.items(.header)[sect_id].addr > addr;
1341 };
1342 const stubs_moved = blk: {
1343 const sect_id = self.stubs_section_index orelse break :blk false;
1344 break :blk self.sections.items(.header)[sect_id].addr > addr;
1345 };
1346
1335 for (self.relocs.values()) |*relocs| {1347 for (self.relocs.values()) |*relocs| {
1336 for (relocs.items) |*reloc| {1348 for (relocs.items) |*reloc| {
1337 const target_addr = reloc.getTargetBaseAddress(self) orelse continue;1349 if (reloc.isGotIndirection()) {
1338 if (target_addr < addr) continue;1350 reloc.dirty = reloc.dirty or got_moved;
1339 reloc.dirty = true;1351 } else if (reloc.isStubTrampoline(self)) {
1352 reloc.dirty = reloc.dirty or stubs_moved;
1353 } else {
1354 const target_addr = reloc.getTargetBaseAddress(self) orelse continue;
1355 if (target_addr > addr) reloc.dirty = true;
1356 }
1340 }1357 }
1341 }1358 }
13421359
1343 // TODO: dirty only really affected GOT cells1360 // TODO: dirty only really affected GOT cells
1344 for (self.got_table.entries.items) |entry| {1361 for (self.got_table.entries.items) |entry| {
1345 const target_addr = self.getSymbol(entry).n_value;1362 const target_addr = self.getSymbol(entry).n_value;
1346 if (target_addr >= addr) {1363 if (target_addr > addr) {
1347 self.got_table_contents_dirty = true;1364 self.got_table_contents_dirty = true;
1348 break;1365 break;
1349 }1366 }
...@@ -1353,7 +1370,7 @@ fn markRelocsDirtyByAddress(self: *MachO, addr: u64) void {...@@ -1353,7 +1370,7 @@ fn markRelocsDirtyByAddress(self: *MachO, addr: u64) void {
1353 const stubs_addr = self.getSegment(self.stubs_section_index.?).vmaddr;1370 const stubs_addr = self.getSegment(self.stubs_section_index.?).vmaddr;
1354 const stub_helper_addr = self.getSegment(self.stub_helper_section_index.?).vmaddr;1371 const stub_helper_addr = self.getSegment(self.stub_helper_section_index.?).vmaddr;
1355 const laptr_addr = self.getSegment(self.la_symbol_ptr_section_index.?).vmaddr;1372 const laptr_addr = self.getSegment(self.la_symbol_ptr_section_index.?).vmaddr;
1356 if (stubs_addr >= addr or stub_helper_addr >= addr or laptr_addr >= addr)1373 if (stubs_addr > addr or stub_helper_addr > addr or laptr_addr > addr)
1357 self.stub_table_contents_dirty = true;1374 self.stub_table_contents_dirty = true;
1358 }1375 }
1359}1376}
...@@ -2794,7 +2811,7 @@ fn growSection(self: *MachO, sect_id: u8, needed_size: u64) !void {...@@ -2794,7 +2811,7 @@ fn growSection(self: *MachO, sect_id: u8, needed_size: u64) !void {
27942811
2795 const sect_vm_capacity = self.allocatedVirtualSize(segment.vmaddr);2812 const sect_vm_capacity = self.allocatedVirtualSize(segment.vmaddr);
2796 if (needed_size > sect_vm_capacity) {2813 if (needed_size > sect_vm_capacity) {
2797 self.markRelocsDirtyByAddress(segment.vmaddr + needed_size);2814 self.markRelocsDirtyByAddress(segment.vmaddr + segment.vmsize);
2798 try self.growSectionVirtualMemory(sect_id, needed_size);2815 try self.growSectionVirtualMemory(sect_id, needed_size);
2799 }2816 }
28002817
...@@ -4067,11 +4084,12 @@ pub fn findFirst(comptime T: type, haystack: []align(1) const T, start: usize, p...@@ -4067,11 +4084,12 @@ pub fn findFirst(comptime T: type, haystack: []align(1) const T, start: usize, p
4067pub fn logSections(self: *MachO) void {4084pub fn logSections(self: *MachO) void {
4068 log.debug("sections:", .{});4085 log.debug("sections:", .{});
4069 for (self.sections.items(.header), 0..) |header, i| {4086 for (self.sections.items(.header), 0..) |header, i| {
4070 log.debug(" sect({d}): {s},{s} @{x}, sizeof({x})", .{4087 log.debug(" sect({d}): {s},{s} @{x} ({x}), sizeof({x})", .{
4071 i + 1,4088 i + 1,
4072 header.segName(),4089 header.segName(),
4073 header.sectName(),4090 header.sectName(),
4074 header.offset,4091 header.offset,
4092 header.addr,
4075 header.size,4093 header.size,
4076 });4094 });
4077 }4095 }
src/link/MachO/Relocation.zig+27-14
...@@ -37,14 +37,33 @@ pub const Type = enum {...@@ -37,14 +37,33 @@ pub const Type = enum {
37 tlv_initializer,37 tlv_initializer,
38};38};
3939
40/// Returns true if and only if the reloc is dirty AND the target address is available.40/// Returns true if and only if the reloc can be resolved.
41pub fn isResolvable(self: Relocation, macho_file: *MachO) bool {41pub fn isResolvable(self: Relocation, macho_file: *MachO) bool {
42 const addr = self.getTargetBaseAddress(macho_file) orelse return false;42 _ = self.getTargetBaseAddress(macho_file) orelse return false;
43 if (addr == 0) return false;43 return true;
44 return self.dirty;44}
45
46pub fn isGotIndirection(self: Relocation) bool {
47 return switch (self.type) {
48 .got, .got_page, .got_pageoff => true,
49 else => false,
50 };
51}
52
53pub fn isStubTrampoline(self: Relocation, macho_file: *MachO) bool {
54 return switch (self.type) {
55 .branch => macho_file.getSymbol(self.target).undf(),
56 else => false,
57 };
45}58}
4659
47pub fn getTargetBaseAddress(self: Relocation, macho_file: *MachO) ?u64 {60pub fn getTargetBaseAddress(self: Relocation, macho_file: *MachO) ?u64 {
61 if (self.isStubTrampoline(macho_file)) {
62 const index = macho_file.stub_table.lookup.get(self.target) orelse return null;
63 const header = macho_file.sections.items(.header)[macho_file.stubs_section_index.?];
64 return header.addr +
65 index * @import("stubs.zig").calcStubEntrySize(macho_file.base.options.target.cpu.arch);
66 }
48 switch (self.type) {67 switch (self.type) {
49 .got, .got_page, .got_pageoff => {68 .got, .got_page, .got_pageoff => {
50 const got_index = macho_file.got_table.lookup.get(self.target) orelse return null;69 const got_index = macho_file.got_table.lookup.get(self.target) orelse return null;
...@@ -56,17 +75,11 @@ pub fn getTargetBaseAddress(self: Relocation, macho_file: *MachO) ?u64 {...@@ -56,17 +75,11 @@ pub fn getTargetBaseAddress(self: Relocation, macho_file: *MachO) ?u64 {
56 const atom = macho_file.getAtom(atom_index);75 const atom = macho_file.getAtom(atom_index);
57 return atom.getSymbol(macho_file).n_value;76 return atom.getSymbol(macho_file).n_value;
58 },77 },
59 .branch => {78 else => {
60 if (macho_file.stub_table.lookup.get(self.target)) |index| {79 const target_atom_index = macho_file.getAtomIndexForSymbol(self.target) orelse return null;
61 const header = macho_file.sections.items(.header)[macho_file.stubs_section_index.?];80 const target_atom = macho_file.getAtom(target_atom_index);
62 return header.addr +81 return target_atom.getSymbol(macho_file).n_value;
63 index * @import("stubs.zig").calcStubEntrySize(macho_file.base.options.target.cpu.arch);
64 }
65 const atom_index = macho_file.getAtomIndexForSymbol(self.target) orelse return null;
66 const atom = macho_file.getAtom(atom_index);
67 return atom.getSymbol(macho_file).n_value;
68 },82 },
69 else => return macho_file.getSymbol(self.target).n_value,
70 }83 }
71}84}
7285
test/behavior/bugs/1851.zig-4
...@@ -16,10 +16,6 @@ test "allocation and looping over 3-byte integer" {...@@ -16,10 +16,6 @@ test "allocation and looping over 3-byte integer" {
16 return error.SkipZigTest; // TODO16 return error.SkipZigTest; // TODO
17 }17 }
1818
19 if (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag == .macos) {
20 return error.SkipZigTest; // TODO
21 }
22
23 try expect(@sizeOf(u24) == 4);19 try expect(@sizeOf(u24) == 4);
24 try expect(@sizeOf([1]u24) == 4);20 try expect(@sizeOf([1]u24) == 4);
25 try expect(@alignOf(u24) == 4);21 try expect(@alignOf(u24) == 4);