authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-11-12 12:17:38-08:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-11-13 07:28:20-08:00
log1d55705fa42d83556346f8fcb3a8fce0d55f06ad
treeebebae2d4ec2b7c5854d8ab31153970478a8d27e
parentd3a099c14fe9b7b575a0cd7bb9cd05b49625a71e

macho: invalidate relocs after relinking relocatables


2 files changed, 100 insertions(+), 10 deletions(-)

src/link/MachO.zig+58-8
...@@ -162,7 +162,10 @@ strtab: std.ArrayListUnmanaged(u8) = .{},...@@ -162,7 +162,10 @@ strtab: std.ArrayListUnmanaged(u8) = .{},
162strtab_dir: std.HashMapUnmanaged(u32, void, StringIndexContext, std.hash_map.default_max_load_percentage) = .{},162strtab_dir: std.HashMapUnmanaged(u32, void, StringIndexContext, std.hash_map.default_max_load_percentage) = .{},
163163
164got_entries_map: std.AutoArrayHashMapUnmanaged(Atom.Relocation.Target, *Atom) = .{},164got_entries_map: std.AutoArrayHashMapUnmanaged(Atom.Relocation.Target, *Atom) = .{},
165got_entries_map_free_list: std.ArrayListUnmanaged(u32) = .{},
166
165stubs_map: std.AutoArrayHashMapUnmanaged(u32, *Atom) = .{},167stubs_map: std.AutoArrayHashMapUnmanaged(u32, *Atom) = .{},
168stubs_map_free_list: std.ArrayListUnmanaged(u32) = .{},
166169
167error_flags: File.ErrorFlags = File.ErrorFlags{},170error_flags: File.ErrorFlags = File.ErrorFlags{},
168171
...@@ -175,6 +178,7 @@ has_stabs: bool = false,...@@ -175,6 +178,7 @@ has_stabs: bool = false,
175/// TODO once we add opening a prelinked output binary from file, this will become178/// TODO once we add opening a prelinked output binary from file, this will become
176/// obsolete as we will carry on where we left off.179/// obsolete as we will carry on where we left off.
177cold_start: bool = false,180cold_start: bool = false,
181invalidate_relocs: bool = false,
178182
179section_ordinals: std.AutoArrayHashMapUnmanaged(MatchingSection, void) = .{},183section_ordinals: std.AutoArrayHashMapUnmanaged(MatchingSection, void) = .{},
180184
...@@ -610,9 +614,24 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {...@@ -610,9 +614,24 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
610 sym.n_desc = 0;614 sym.n_desc = 0;
611 },615 },
612 }616 }
617 if (self.got_entries_map.getIndex(.{ .global = entry.key })) |i| {
618 self.got_entries_map_free_list.append(
619 self.base.allocator,
620 @intCast(u32, i),
621 ) catch {};
622 self.got_entries_map.keys()[i] = .{ .local = 0 };
623 }
624 if (self.stubs_map.getIndex(entry.key)) |i| {
625 self.stubs_map_free_list.append(self.base.allocator, @intCast(u32, i)) catch {};
626 self.stubs_map.keys()[i] = 0;
627 }
613 }628 }
614 }629 }
615 }630 }
631 // Invalidate all relocs
632 // TODO we only need to invalidate the backlinks to the relinked atoms from
633 // the relocatable object files.
634 self.invalidate_relocs = true;
616635
617 // Positional arguments to the linker such as object files and static archives.636 // Positional arguments to the linker such as object files and static archives.
618 var positionals = std.ArrayList([]const u8).init(arena);637 var positionals = std.ArrayList([]const u8).init(arena);
...@@ -889,6 +908,19 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {...@@ -889,6 +908,19 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
889 }908 }
890 }909 }
891910
911 log.debug("GOT entries:", .{});
912 for (self.got_entries_map.keys()) |key| {
913 switch (key) {
914 .local => |sym_index| log.debug(" {} => {d}", .{ key, sym_index }),
915 .global => |n_strx| log.debug(" {} => {s}", .{ key, self.getString(n_strx) }),
916 }
917 }
918
919 log.debug("stubs:", .{});
920 for (self.stubs_map.keys()) |key| {
921 log.debug(" {} => {s}", .{ key, self.getString(key) });
922 }
923
892 try self.writeAtoms();924 try self.writeAtoms();
893925
894 if (self.bss_section_index) |idx| {926 if (self.bss_section_index) |idx| {
...@@ -1838,7 +1870,7 @@ fn writeAtoms(self: *MachO) !void {...@@ -1838,7 +1870,7 @@ fn writeAtoms(self: *MachO) !void {
1838 }1870 }
18391871
1840 while (true) {1872 while (true) {
1841 if (atom.dirty) {1873 if (atom.dirty or self.invalidate_relocs) {
1842 const atom_sym = self.locals.items[atom.local_sym_index];1874 const atom_sym = self.locals.items[atom.local_sym_index];
1843 const padding_size: u64 = if (atom.next) |next| blk: {1875 const padding_size: u64 = if (atom.next) |next| blk: {
1844 const next_sym = self.locals.items[next.local_sym_index];1876 const next_sym = self.locals.items[next.local_sym_index];
...@@ -2907,7 +2939,9 @@ pub fn deinit(self: *MachO) void {...@@ -2907,7 +2939,9 @@ pub fn deinit(self: *MachO) void {
29072939
2908 self.section_ordinals.deinit(self.base.allocator);2940 self.section_ordinals.deinit(self.base.allocator);
2909 self.got_entries_map.deinit(self.base.allocator);2941 self.got_entries_map.deinit(self.base.allocator);
2942 self.got_entries_map_free_list.deinit(self.base.allocator);
2910 self.stubs_map.deinit(self.base.allocator);2943 self.stubs_map.deinit(self.base.allocator);
2944 self.stubs_map_free_list.deinit(self.base.allocator);
2911 self.strtab_dir.deinit(self.base.allocator);2945 self.strtab_dir.deinit(self.base.allocator);
2912 self.strtab.deinit(self.base.allocator);2946 self.strtab.deinit(self.base.allocator);
2913 self.undefs.deinit(self.base.allocator);2947 self.undefs.deinit(self.base.allocator);
...@@ -3091,8 +3125,22 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {...@@ -3091,8 +3125,22 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {
30913125
3092 // TODO try popping from free list first before allocating a new GOT atom.3126 // TODO try popping from free list first before allocating a new GOT atom.
3093 const target = Atom.Relocation.Target{ .local = decl.link.macho.local_sym_index };3127 const target = Atom.Relocation.Target{ .local = decl.link.macho.local_sym_index };
3094 const got_atom = try self.createGotAtom(target);3128 const value_ptr = blk: {
3095 try self.got_entries_map.put(self.base.allocator, target, got_atom);3129 if (self.got_entries_map_free_list.popOrNull()) |i| {
3130 log.debug("reusing GOT entry index {d} for {s}", .{ i, decl.name });
3131 self.got_entries_map.keys()[i] = target;
3132 const value_ptr = self.got_entries_map.getPtr(target).?;
3133 break :blk value_ptr;
3134 } else {
3135 const res = try self.got_entries_map.getOrPut(self.base.allocator, target);
3136 log.debug("creating new GOT entry at index {d} for {s}", .{
3137 self.got_entries_map.getIndex(target).?,
3138 decl.name,
3139 });
3140 break :blk res.value_ptr;
3141 }
3142 };
3143 value_ptr.* = try self.createGotAtom(target);
3096}3144}
30973145
3098pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {3146pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {
...@@ -3516,7 +3564,9 @@ pub fn freeDecl(self: *MachO, decl: *Module.Decl) void {...@@ -3516,7 +3564,9 @@ pub fn freeDecl(self: *MachO, decl: *Module.Decl) void {
3516 if (decl.link.macho.local_sym_index != 0) {3564 if (decl.link.macho.local_sym_index != 0) {
3517 self.locals_free_list.append(self.base.allocator, decl.link.macho.local_sym_index) catch {};3565 self.locals_free_list.append(self.base.allocator, decl.link.macho.local_sym_index) catch {};
35183566
3519 // TODO free GOT atom here.3567 // Try freeing GOT atom
3568 const got_index = self.got_entries_map.getIndex(.{ .local = decl.link.macho.local_sym_index }).?;
3569 self.got_entries_map_free_list.append(self.base.allocator, @intCast(u32, got_index)) catch {};
35203570
3521 self.locals.items[decl.link.macho.local_sym_index].n_type = 0;3571 self.locals.items[decl.link.macho.local_sym_index].n_type = 0;
3522 decl.link.macho.local_sym_index = 0;3572 decl.link.macho.local_sym_index = 0;
...@@ -4907,7 +4957,7 @@ fn writeSymbolTable(self: *MachO) !void {...@@ -4907,7 +4957,7 @@ fn writeSymbolTable(self: *MachO) !void {
49074957
4908 stubs.reserved1 = 0;4958 stubs.reserved1 = 0;
4909 for (self.stubs_map.keys()) |key| {4959 for (self.stubs_map.keys()) |key| {
4910 const resolv = self.symbol_resolver.get(key).?;4960 const resolv = self.symbol_resolver.get(key) orelse continue;
4911 switch (resolv.where) {4961 switch (resolv.where) {
4912 .global => try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL),4962 .global => try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL),
4913 .undef => try writer.writeIntLittle(u32, dysymtab.iundefsym + resolv.where_index),4963 .undef => try writer.writeIntLittle(u32, dysymtab.iundefsym + resolv.where_index),
...@@ -4919,7 +4969,7 @@ fn writeSymbolTable(self: *MachO) !void {...@@ -4919,7 +4969,7 @@ fn writeSymbolTable(self: *MachO) !void {
4919 switch (key) {4969 switch (key) {
4920 .local => try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL),4970 .local => try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL),
4921 .global => |n_strx| {4971 .global => |n_strx| {
4922 const resolv = self.symbol_resolver.get(n_strx).?;4972 const resolv = self.symbol_resolver.get(n_strx) orelse continue;
4923 switch (resolv.where) {4973 switch (resolv.where) {
4924 .global => try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL),4974 .global => try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL),
4925 .undef => try writer.writeIntLittle(u32, dysymtab.iundefsym + resolv.where_index),4975 .undef => try writer.writeIntLittle(u32, dysymtab.iundefsym + resolv.where_index),
...@@ -4930,7 +4980,7 @@ fn writeSymbolTable(self: *MachO) !void {...@@ -4930,7 +4980,7 @@ fn writeSymbolTable(self: *MachO) !void {
49304980
4931 la_symbol_ptr.reserved1 = got.reserved1 + ngot_entries;4981 la_symbol_ptr.reserved1 = got.reserved1 + ngot_entries;
4932 for (self.stubs_map.keys()) |key| {4982 for (self.stubs_map.keys()) |key| {
4933 const resolv = self.symbol_resolver.get(key).?;4983 const resolv = self.symbol_resolver.get(key) orelse continue;
4934 switch (resolv.where) {4984 switch (resolv.where) {
4935 .global => try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL),4985 .global => try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL),
4936 .undef => try writer.writeIntLittle(u32, dysymtab.iundefsym + resolv.where_index),4986 .undef => try writer.writeIntLittle(u32, dysymtab.iundefsym + resolv.where_index),
...@@ -5346,7 +5396,7 @@ fn snapshotState(self: *MachO) !void {...@@ -5346,7 +5396,7 @@ fn snapshotState(self: *MachO) !void {
5346 };5396 };
53475397
5348 if (is_via_got) {5398 if (is_via_got) {
5349 const got_atom = self.got_entries_map.get(rel.target).?;5399 const got_atom = self.got_entries_map.get(rel.target) orelse break :blk 0;
5350 break :blk self.locals.items[got_atom.local_sym_index].n_value;5400 break :blk self.locals.items[got_atom.local_sym_index].n_value;
5351 }5401 }
53525402
src/link/MachO/Atom.zig+42-2
...@@ -524,8 +524,28 @@ fn addPtrBindingOrRebase(...@@ -524,8 +524,28 @@ fn addPtrBindingOrRebase(
524524
525fn addGotEntry(target: Relocation.Target, context: RelocContext) !void {525fn addGotEntry(target: Relocation.Target, context: RelocContext) !void {
526 if (context.macho_file.got_entries_map.contains(target)) return;526 if (context.macho_file.got_entries_map.contains(target)) return;
527
528 const value_ptr = blk: {
529 if (context.macho_file.got_entries_map_free_list.popOrNull()) |i| {
530 log.debug("reusing GOT entry index {d} for {}", .{ i, target });
531 context.macho_file.got_entries_map.keys()[i] = target;
532 const value_ptr = context.macho_file.got_entries_map.getPtr(target).?;
533 break :blk value_ptr;
534 } else {
535 const res = try context.macho_file.got_entries_map.getOrPut(
536 context.macho_file.base.allocator,
537 target,
538 );
539 log.debug("creating new GOT entry at index {d} for {}", .{
540 context.macho_file.got_entries_map.getIndex(target).?,
541 target,
542 });
543 break :blk res.value_ptr;
544 }
545 };
527 const atom = try context.macho_file.createGotAtom(target);546 const atom = try context.macho_file.createGotAtom(target);
528 try context.macho_file.got_entries_map.putNoClobber(context.macho_file.base.allocator, target, atom);547 value_ptr.* = atom;
548
529 const match = MachO.MatchingSection{549 const match = MachO.MatchingSection{
530 .seg = context.macho_file.data_const_segment_cmd_index.?,550 .seg = context.macho_file.data_const_segment_cmd_index.?,
531 .sect = context.macho_file.got_section_index.?,551 .sect = context.macho_file.got_section_index.?,
...@@ -545,6 +565,26 @@ fn addGotEntry(target: Relocation.Target, context: RelocContext) !void {...@@ -545,6 +565,26 @@ fn addGotEntry(target: Relocation.Target, context: RelocContext) !void {
545fn addStub(target: Relocation.Target, context: RelocContext) !void {565fn addStub(target: Relocation.Target, context: RelocContext) !void {
546 if (target != .global) return;566 if (target != .global) return;
547 if (context.macho_file.stubs_map.contains(target.global)) return;567 if (context.macho_file.stubs_map.contains(target.global)) return;
568
569 const value_ptr = blk: {
570 if (context.macho_file.stubs_map_free_list.popOrNull()) |i| {
571 log.debug("reusing stubs entry index {d} for {}", .{ i, target });
572 context.macho_file.stubs_map.keys()[i] = target.global;
573 const value_ptr = context.macho_file.stubs_map.getPtr(target.global).?;
574 break :blk value_ptr;
575 } else {
576 const res = try context.macho_file.stubs_map.getOrPut(
577 context.macho_file.base.allocator,
578 target.global,
579 );
580 log.debug("creating new stubs entry at index {d} for {}", .{
581 context.macho_file.stubs_map.getIndex(target.global).?,
582 target,
583 });
584 break :blk res.value_ptr;
585 }
586 };
587
548 // TODO clean this up!588 // TODO clean this up!
549 const stub_helper_atom = atom: {589 const stub_helper_atom = atom: {
550 const atom = try context.macho_file.createStubHelperAtom();590 const atom = try context.macho_file.createStubHelperAtom();
...@@ -600,7 +640,7 @@ fn addStub(target: Relocation.Target, context: RelocContext) !void {...@@ -600,7 +640,7 @@ fn addStub(target: Relocation.Target, context: RelocContext) !void {
600 } else {640 } else {
601 try context.object.end_atoms.putNoClobber(context.allocator, match, atom);641 try context.object.end_atoms.putNoClobber(context.allocator, match, atom);
602 }642 }
603 try context.macho_file.stubs_map.putNoClobber(context.allocator, target.global, atom);643 value_ptr.* = atom;
604}644}
605645
606pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void {646pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void {