authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-09-18 15:13:45+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-09-18 15:13:45+02:00
log4474f8dd6ed58875930f440aad0b893c1c9a414d
treed663e4dbc44484992442e177a6bf41d0231662b3
parentf4706c23e9aadb53dd6620107ae5c7676e2dab86

macho: cleanup how we collect dyld data in incremental linker


1 files changed, 151 insertions(+), 136 deletions(-)

src/link/MachO.zig+151-136
......@@ -4033,14 +4033,6 @@ fn writeLinkeditSegmentData(self: *MachO, ncmds: *u32, lc_writer: anytype) !void
40334033 seg.fileoff = mem.alignForwardGeneric(u64, segment.fileoff + segment.filesize, self.page_size);
40344034 }
40354035 }
4036 // seg.vmaddr = blk: {
4037 // const prev_segment = self.segments.items[self.linkedit_segment_cmd_index.? - 1];
4038 // break :blk mem.alignForwardGeneric(u64, prev_segment.vmaddr + prev_segment.vmsize, self.page_size);
4039 // };
4040 // seg.fileoff = blk: {
4041 // const prev_segment = self.segments.items[self.linkedit_segment_cmd_index.? - 1];
4042 // break :blk mem.alignForwardGeneric(u64, prev_segment.fileoff + prev_segment.filesize, self.page_size);
4043 // };
40444036
40454037 try self.writeDyldInfoData(ncmds, lc_writer);
40464038 try self.writeSymtabs(ncmds, lc_writer);
......@@ -4048,153 +4040,176 @@ fn writeLinkeditSegmentData(self: *MachO, ncmds: *u32, lc_writer: anytype) !void
40484040 seg.vmsize = mem.alignForwardGeneric(u64, seg.filesize, self.page_size);
40494041}
40504042
4051fn writeDyldInfoData(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {
4052 const tracy = trace(@src());
4053 defer tracy.end();
4043const AtomLessThanByAddressContext = struct {
4044 macho_file: *MachO,
4045};
4046
4047fn atomLessThanByAddress(ctx: AtomLessThanByAddressContext, lhs: *Atom, rhs: *Atom) bool {
4048 return lhs.getSymbol(ctx.macho_file).n_value < rhs.getSymbol(ctx.macho_file).n_value;
4049}
40544050
4051fn collectRebaseData(self: *MachO, pointers: *std.ArrayList(bind.Pointer)) !void {
40554052 const gpa = self.base.allocator;
40564053
4057 var rebase_pointers = std.ArrayList(bind.Pointer).init(gpa);
4058 defer rebase_pointers.deinit();
4059 var bind_pointers = std.ArrayList(bind.Pointer).init(gpa);
4060 defer bind_pointers.deinit();
4061 var lazy_bind_pointers = std.ArrayList(bind.Pointer).init(gpa);
4062 defer lazy_bind_pointers.deinit();
4054 var sorted_atoms_by_address = std.ArrayList(*Atom).init(gpa);
4055 defer sorted_atoms_by_address.deinit();
4056 try sorted_atoms_by_address.ensureTotalCapacityPrecise(self.rebases.count());
40634057
4064 const slice = self.sections.slice();
4065 for (slice.items(.last_atom)) |last_atom, sect_id| {
4066 var atom = last_atom orelse continue;
4067 const header = slice.items(.header)[sect_id];
4068 const segment_index = slice.items(.segment_index)[sect_id];
4069 const seg = self.getSegment(@intCast(u8, sect_id));
4058 var it = self.rebases.keyIterator();
4059 while (it.next()) |key_ptr| {
4060 sorted_atoms_by_address.appendAssumeCapacity(key_ptr.*);
4061 }
40704062
4071 if (mem.eql(u8, header.segName(), "__TEXT")) continue; // __TEXT is non-writable
4063 std.sort.sort(*Atom, sorted_atoms_by_address.items, AtomLessThanByAddressContext{
4064 .macho_file = self,
4065 }, atomLessThanByAddress);
40724066
4073 log.debug("dyld info for {s},{s}", .{ header.segName(), header.sectName() });
4067 const slice = self.sections.slice();
4068 for (sorted_atoms_by_address.items) |atom| {
4069 log.debug(" ATOM(%{d}, '{s}')", .{ atom.sym_index, atom.getName(self) });
40744070
4075 while (true) {
4076 log.debug(" ATOM(%{d}, '{s}')", .{ atom.sym_index, atom.getName(self) });
4077 const sym = atom.getSymbol(self);
4078 const base_offset = sym.n_value - seg.vmaddr;
4079
4080 if (self.rebases.get(atom)) |rebases| {
4081 for (rebases.items) |offset| {
4082 log.debug(" | rebase at {x}", .{base_offset + offset});
4083 try rebase_pointers.append(.{
4084 .offset = base_offset + offset,
4085 .segment_id = segment_index,
4086 });
4087 }
4088 }
4071 const sym = atom.getSymbol(self);
4072 const segment_index = slice.items(.segment_index)[sym.n_sect - 1];
4073 const seg = self.getSegment(sym.n_sect - 1);
40894074
4090 if (self.bindings.get(atom)) |bindings| {
4091 for (bindings.items) |binding| {
4092 const bind_sym = self.getSymbol(binding.target);
4093 const bind_sym_name = self.getSymbolName(binding.target);
4094 const dylib_ordinal = @divTrunc(
4095 @bitCast(i16, bind_sym.n_desc),
4096 macho.N_SYMBOL_RESOLVER,
4097 );
4098 var flags: u4 = 0;
4099 log.debug(" | bind at {x}, import('{s}') in dylib({d})", .{
4100 binding.offset + base_offset,
4101 bind_sym_name,
4102 dylib_ordinal,
4103 });
4104 if (bind_sym.weakRef()) {
4105 log.debug(" | marking as weak ref ", .{});
4106 flags |= @truncate(u4, macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT);
4107 }
4108 try bind_pointers.append(.{
4109 .offset = binding.offset + base_offset,
4110 .segment_id = segment_index,
4111 .dylib_ordinal = dylib_ordinal,
4112 .name = bind_sym_name,
4113 .bind_flags = flags,
4114 });
4115 }
4116 }
4075 const base_offset = sym.n_value - seg.vmaddr;
41174076
4118 if (self.lazy_bindings.get(atom)) |lazy_bindings| {
4119 for (lazy_bindings.items) |binding| {
4120 const bind_sym = self.getSymbol(binding.target);
4121 const bind_sym_name = self.getSymbolName(binding.target);
4122 const dylib_ordinal = @divTrunc(
4123 @bitCast(i16, bind_sym.n_desc),
4124 macho.N_SYMBOL_RESOLVER,
4125 );
4126 var flags: u4 = 0;
4127 log.debug(" | lazy bind at {x} import('{s}') ord({d})", .{
4128 binding.offset + base_offset,
4129 bind_sym_name,
4130 dylib_ordinal,
4131 });
4132 if (bind_sym.weakRef()) {
4133 log.debug(" | marking as weak ref ", .{});
4134 flags |= @truncate(u4, macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT);
4135 }
4136 try lazy_bind_pointers.append(.{
4137 .offset = binding.offset + base_offset,
4138 .segment_id = segment_index,
4139 .dylib_ordinal = dylib_ordinal,
4140 .name = bind_sym_name,
4141 .bind_flags = flags,
4142 });
4143 }
4144 }
4077 const rebases = self.rebases.get(atom).?;
4078 try pointers.ensureUnusedCapacity(rebases.items.len);
4079 for (rebases.items) |offset| {
4080 log.debug(" | rebase at {x}", .{base_offset + offset});
41454081
4146 if (atom.prev) |prev| {
4147 atom = prev;
4148 } else break;
4082 pointers.appendAssumeCapacity(.{
4083 .offset = base_offset + offset,
4084 .segment_id = segment_index,
4085 });
41494086 }
41504087 }
4088}
41514089
4152 var trie: Trie = .{};
4153 defer trie.deinit(gpa);
4090fn collectBindData(self: *MachO, pointers: *std.ArrayList(bind.Pointer), raw_bindings: anytype) !void {
4091 const gpa = self.base.allocator;
41544092
4155 {
4156 // TODO handle macho.EXPORT_SYMBOL_FLAGS_REEXPORT and macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER.
4157 log.debug("generating export trie", .{});
4158
4159 const text_segment = self.segments.items[self.header_segment_cmd_index.?];
4160 const base_address = text_segment.vmaddr;
4161
4162 if (self.base.options.output_mode == .Exe) {
4163 for (&[_]SymbolWithLoc{
4164 try self.getEntryPoint(),
4165 self.getGlobal("__mh_execute_header").?,
4166 }) |global| {
4167 const sym = self.getSymbol(global);
4168 const sym_name = self.getSymbolName(global);
4169 log.debug(" (putting '{s}' defined at 0x{x})", .{ sym_name, sym.n_value });
4170 try trie.put(gpa, .{
4171 .name = sym_name,
4172 .vmaddr_offset = sym.n_value - base_address,
4173 .export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR,
4174 });
4175 }
4176 } else {
4177 assert(self.base.options.output_mode == .Lib);
4178 for (self.globals.items) |global| {
4179 const sym = self.getSymbol(global);
4180
4181 if (sym.undf()) continue;
4182 if (!sym.ext()) continue;
4183 if (sym.n_desc == N_DESC_GCED) continue;
4184
4185 const sym_name = self.getSymbolName(global);
4186 log.debug(" (putting '{s}' defined at 0x{x})", .{ sym_name, sym.n_value });
4187 try trie.put(gpa, .{
4188 .name = sym_name,
4189 .vmaddr_offset = sym.n_value - base_address,
4190 .export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR,
4191 });
4093 var sorted_atoms_by_address = std.ArrayList(*Atom).init(gpa);
4094 defer sorted_atoms_by_address.deinit();
4095 try sorted_atoms_by_address.ensureTotalCapacityPrecise(raw_bindings.count());
4096
4097 var it = raw_bindings.keyIterator();
4098 while (it.next()) |key_ptr| {
4099 sorted_atoms_by_address.appendAssumeCapacity(key_ptr.*);
4100 }
4101
4102 std.sort.sort(*Atom, sorted_atoms_by_address.items, AtomLessThanByAddressContext{
4103 .macho_file = self,
4104 }, atomLessThanByAddress);
4105
4106 const slice = self.sections.slice();
4107 for (sorted_atoms_by_address.items) |atom| {
4108 log.debug(" ATOM(%{d}, '{s}')", .{ atom.sym_index, atom.getName(self) });
4109
4110 const sym = atom.getSymbol(self);
4111 const segment_index = slice.items(.segment_index)[sym.n_sect - 1];
4112 const seg = self.getSegment(sym.n_sect - 1);
4113
4114 const base_offset = sym.n_value - seg.vmaddr;
4115
4116 const bindings = raw_bindings.get(atom).?;
4117 try pointers.ensureUnusedCapacity(bindings.items.len);
4118 for (bindings.items) |binding| {
4119 const bind_sym = self.getSymbol(binding.target);
4120 const bind_sym_name = self.getSymbolName(binding.target);
4121 const dylib_ordinal = @divTrunc(
4122 @bitCast(i16, bind_sym.n_desc),
4123 macho.N_SYMBOL_RESOLVER,
4124 );
4125 var flags: u4 = 0;
4126 log.debug(" | bind at {x}, import('{s}') in dylib({d})", .{
4127 binding.offset + base_offset,
4128 bind_sym_name,
4129 dylib_ordinal,
4130 });
4131 if (bind_sym.weakRef()) {
4132 log.debug(" | marking as weak ref ", .{});
4133 flags |= @truncate(u4, macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT);
41924134 }
4135 pointers.appendAssumeCapacity(.{
4136 .offset = binding.offset + base_offset,
4137 .segment_id = segment_index,
4138 .dylib_ordinal = dylib_ordinal,
4139 .name = bind_sym_name,
4140 .bind_flags = flags,
4141 });
41934142 }
4143 }
4144}
4145
4146fn collectExportData(self: *MachO, trie: *Trie) !void {
4147 const gpa = self.base.allocator;
4148
4149 // TODO handle macho.EXPORT_SYMBOL_FLAGS_REEXPORT and macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER.
4150 log.debug("generating export trie", .{});
4151
4152 const exec_segment = self.segments.items[self.header_segment_cmd_index.?];
4153 const base_address = exec_segment.vmaddr;
41944154
4195 try trie.finalize(gpa);
4155 if (self.base.options.output_mode == .Exe) {
4156 for (&[_]SymbolWithLoc{
4157 try self.getEntryPoint(),
4158 self.getGlobal("__mh_execute_header").?,
4159 }) |global| {
4160 const sym = self.getSymbol(global);
4161 const sym_name = self.getSymbolName(global);
4162 log.debug(" (putting '{s}' defined at 0x{x})", .{ sym_name, sym.n_value });
4163 try trie.put(gpa, .{
4164 .name = sym_name,
4165 .vmaddr_offset = sym.n_value - base_address,
4166 .export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR,
4167 });
4168 }
4169 } else {
4170 assert(self.base.options.output_mode == .Lib);
4171 for (self.globals.items) |global| {
4172 const sym = self.getSymbol(global);
4173
4174 if (sym.undf()) continue;
4175 if (!sym.ext()) continue;
4176 if (sym.n_desc == N_DESC_GCED) continue;
4177
4178 const sym_name = self.getSymbolName(global);
4179 log.debug(" (putting '{s}' defined at 0x{x})", .{ sym_name, sym.n_value });
4180 try trie.put(gpa, .{
4181 .name = sym_name,
4182 .vmaddr_offset = sym.n_value - base_address,
4183 .export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR,
4184 });
4185 }
41964186 }
41974187
4188 try trie.finalize(gpa);
4189}
4190
4191fn writeDyldInfoData(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {
4192 const tracy = trace(@src());
4193 defer tracy.end();
4194
4195 const gpa = self.base.allocator;
4196
4197 var rebase_pointers = std.ArrayList(bind.Pointer).init(gpa);
4198 defer rebase_pointers.deinit();
4199 try self.collectRebaseData(&rebase_pointers);
4200
4201 var bind_pointers = std.ArrayList(bind.Pointer).init(gpa);
4202 defer bind_pointers.deinit();
4203 try self.collectBindData(&bind_pointers, self.bindings);
4204
4205 var lazy_bind_pointers = std.ArrayList(bind.Pointer).init(gpa);
4206 defer lazy_bind_pointers.deinit();
4207 try self.collectBindData(&lazy_bind_pointers, self.lazy_bindings);
4208
4209 var trie: Trie = .{};
4210 defer trie.deinit(gpa);
4211 try self.collectExportData(&trie);
4212
41984213 const link_seg = self.getLinkeditSegmentPtr();
41994214 const rebase_off = mem.alignForwardGeneric(u64, link_seg.fileoff, @alignOf(u64));
42004215 assert(rebase_off == link_seg.fileoff);