authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-05 20:20:07+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-15 18:49:47+02:00
log51e334af447b126862238f0743342755d719f897
tree401cff1f5e4d821047979fa4af38d0e92bf45cda
parent7b4063d55899b0e35711c848f7b19de6f928282b

zld: refactor section into TextBlocks conversion


2 files changed, 153 insertions(+), 99 deletions(-)

src/link/MachO/Object.zig+121-80
......@@ -276,11 +276,11 @@ const NlistWithIndex = struct {
276276 nlist: macho.nlist_64,
277277 index: u32,
278278
279 pub fn cmp(_: void, lhs: @This(), rhs: @This()) bool {
279 fn lessThan(_: void, lhs: @This(), rhs: @This()) bool {
280280 return lhs.nlist.n_value < rhs.nlist.n_value;
281281 }
282282
283 fn filterNlistsInSection(symbols: []@This(), sect_id: u8) []@This() {
283 fn filterInSection(symbols: []@This(), sect_id: u8) []@This() {
284284 var start: usize = 0;
285285 var end: usize = symbols.len;
286286
......@@ -327,19 +327,111 @@ fn filterRelocs(relocs: []macho.relocation_info, start: u64, end: u64) []macho.r
327327 return relocs[start_id..end_id];
328328}
329329
330const SeniorityContext = struct {
330const TextBlockParser = struct {
331 allocator: *Allocator,
332 section: macho.section_64,
333 code: []u8,
334 object: *Object,
331335 zld: *Zld,
332};
333fn cmpSymBySeniority(context: SeniorityContext, lhs: u32, rhs: u32) bool {
334 const lreg = context.zld.locals.items[lhs].payload.regular;
335 const rreg = context.zld.locals.items[rhs].payload.regular;
336
337 return switch (rreg.linkage) {
338 .global => true,
339 .linkage_unit => lreg.linkage == .translation_unit,
340 else => false,
336 nlists: []NlistWithIndex,
337 index: u32 = 0,
338
339 fn peek(self: *TextBlockParser) ?NlistWithIndex {
340 return if (self.index + 1 < self.nlists.len) self.nlists[self.index + 1] else null;
341 }
342
343 const SeniorityContext = struct {
344 zld: *Zld,
341345 };
342}
346
347 fn lessThanBySeniority(context: SeniorityContext, lhs: NlistWithIndex, rhs: NlistWithIndex) bool {
348 const lreg = context.zld.locals.items[lhs.index].payload.regular;
349 const rreg = context.zld.locals.items[rhs.index].payload.regular;
350
351 return switch (rreg.linkage) {
352 .global => true,
353 .linkage_unit => lreg.linkage == .translation_unit,
354 else => false,
355 };
356 }
357
358 pub fn next(self: *TextBlockParser) !?*TextBlock {
359 if (self.index == self.nlists.len) return null;
360
361 var aliases = std.ArrayList(NlistWithIndex).init(self.allocator);
362 defer aliases.deinit();
363
364 const next_nlist: ?NlistWithIndex = blk: while (true) {
365 const curr_nlist = self.nlists[self.index];
366 try aliases.append(curr_nlist);
367
368 if (self.peek()) |next_nlist| {
369 if (curr_nlist.nlist.n_value == next_nlist.nlist.n_value) {
370 self.index += 1;
371 continue;
372 }
373 break :blk next_nlist;
374 }
375 break :blk null;
376 } else null;
377
378 for (aliases.items) |*nlist_with_index| {
379 const sym = self.object.symbols.items[nlist_with_index.index];
380 if (sym.payload != .regular) {
381 log.err("expected a regular symbol, found {s}", .{sym.payload});
382 log.err(" when remapping {s}", .{sym.name});
383 return error.SymbolIsNotRegular;
384 }
385 assert(sym.payload.regular.local_sym_index != 0); // This means the symbol has not been properly resolved.
386 nlist_with_index.index = sym.payload.regular.local_sym_index;
387 }
388
389 if (aliases.items.len > 1) {
390 // Bubble-up senior symbol as the main link to the text block.
391 std.sort.sort(
392 NlistWithIndex,
393 aliases.items,
394 SeniorityContext{ .zld = self.zld },
395 @This().lessThanBySeniority,
396 );
397 }
398
399 const senior_nlist = aliases.pop();
400 const senior_sym = self.zld.locals.items[senior_nlist.index];
401 assert(senior_sym.payload == .regular);
402
403 const start_addr = senior_nlist.nlist.n_value - self.section.addr;
404 const end_addr = if (next_nlist) |n| n.nlist.n_value - self.section.addr else self.section.size;
405
406 const code = self.code[start_addr..end_addr];
407 const size = code.len;
408
409 const alias_only_indices = if (aliases.items.len > 0) blk: {
410 var out = std.ArrayList(u32).init(self.allocator);
411 try out.ensureTotalCapacity(aliases.items.len);
412 for (aliases.items) |alias| {
413 out.appendAssumeCapacity(alias.index);
414 }
415 break :blk out.toOwnedSlice();
416 } else null;
417
418 const block = try self.allocator.create(TextBlock);
419 errdefer self.allocator.destroy(block);
420
421 block.* = .{
422 .local_sym_index = senior_nlist.index,
423 .aliases = alias_only_indices,
424 .code = code,
425 .size = size,
426 .alignment = self.section.@"align",
427 };
428
429 self.index += 1;
430 block.print_this(self.zld);
431
432 return block;
433 }
434};
343435
344436pub fn parseTextBlocks(self: *Object, zld: *Zld) !?*TextBlock {
345437 const seg = self.load_commands.items[self.segment_cmd_index.?].Segment;
......@@ -361,7 +453,7 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !?*TextBlock {
361453 });
362454 }
363455
364 std.sort.sort(NlistWithIndex, sorted_nlists.items, {}, NlistWithIndex.cmp);
456 std.sort.sort(NlistWithIndex, sorted_nlists.items, {}, NlistWithIndex.lessThan);
365457
366458 var last_block: ?*TextBlock = null;
367459
......@@ -385,53 +477,26 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !?*TextBlock {
385477 // Is there any padding between symbols within the section?
386478 const is_padded = self.header.?.flags & macho.MH_SUBSECTIONS_VIA_SYMBOLS != 0;
387479
388 // Section alignment will be the assumed alignment per symbol.
389 const alignment = sect.@"align";
390
391480 next: {
392481 if (is_padded) blocks: {
393 const filtered_nlists = NlistWithIndex.filterNlistsInSection(
482 const filtered_nlists = NlistWithIndex.filterInSection(
394483 sorted_nlists.items,
395484 @intCast(u8, sect_id + 1),
396485 );
397486
398487 if (filtered_nlists.len == 0) break :blocks;
399488
400 var nlist_indices = std.ArrayList(u32).init(self.allocator);
401 defer nlist_indices.deinit();
402
403 var i: u32 = 0;
404 while (i < filtered_nlists.len) : (i += 1) {
405 const curr = filtered_nlists[i];
406 try nlist_indices.append(curr.index);
407
408 const next: ?NlistWithIndex = if (i + 1 < filtered_nlists.len)
409 filtered_nlists[i + 1]
410 else
411 null;
412
413 if (next) |n| {
414 if (curr.nlist.n_value == n.nlist.n_value) {
415 continue;
416 }
417 }
418
419 // Bubble-up senior symbol as the main link to the text block.
420 for (nlist_indices.items) |*index| {
421 const sym = self.symbols.items[index.*];
422 if (sym.payload != .regular) {
423 log.err("expected a regular symbol, found {s}", .{sym.payload});
424 log.err(" when remapping {s}", .{sym.name});
425 return error.SymbolIsNotRegular;
426 }
427 assert(sym.payload.regular.local_sym_index != 0); // This means the symbol has not been properly resolved.
428 index.* = sym.payload.regular.local_sym_index;
429 }
430
431 std.sort.sort(u32, nlist_indices.items, SeniorityContext{ .zld = zld }, cmpSymBySeniority);
432
433 const local_sym_index = nlist_indices.pop();
434 const sym = zld.locals.items[local_sym_index];
489 var parser = TextBlockParser{
490 .allocator = self.allocator,
491 .section = sect,
492 .code = code,
493 .object = self,
494 .zld = zld,
495 .nlists = filtered_nlists,
496 };
497
498 while (try parser.next()) |block| {
499 const sym = zld.locals.items[block.local_sym_index];
435500 if (sym.payload.regular.file) |file| {
436501 if (file != self) {
437502 log.warn("deduping definition of {s} in {s}", .{ sym.name, self.name.? });
......@@ -439,27 +504,8 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !?*TextBlock {
439504 }
440505 }
441506
442 const start_addr = curr.nlist.n_value - sect.addr;
443 const end_addr = if (next) |n| n.nlist.n_value - sect.addr else sect.size;
444
445 const tb_code = code[start_addr..end_addr];
446 const size = tb_code.len;
447
448 const block = try self.allocator.create(TextBlock);
449 errdefer self.allocator.destroy(block);
450
451 block.* = .{
452 .local_sym_index = local_sym_index,
453 .aliases = std.ArrayList(u32).init(self.allocator),
454 .references = std.ArrayList(u32).init(self.allocator),
455 .code = tb_code,
456 .relocs = std.ArrayList(*Relocation).init(self.allocator),
457 .size = size,
458 .alignment = alignment,
459 .segment_id = match.seg,
460 .section_id = match.sect,
461 };
462 try block.aliases.appendSlice(nlist_indices.items);
507 block.segment_id = match.seg;
508 block.section_id = match.sect;
463509
464510 // TODO parse relocs
465511
......@@ -468,8 +514,6 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !?*TextBlock {
468514 block.prev = last;
469515 }
470516 last_block = block;
471
472 nlist_indices.clearRetainingCapacity();
473517 }
474518
475519 break :next;
......@@ -498,12 +542,9 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !?*TextBlock {
498542
499543 block.* = .{
500544 .local_sym_index = local_sym_index,
501 .aliases = std.ArrayList(u32).init(self.allocator),
502 .references = std.ArrayList(u32).init(self.allocator),
503545 .code = code,
504 .relocs = std.ArrayList(*Relocation).init(self.allocator),
505546 .size = sect.size,
506 .alignment = alignment,
547 .alignment = sect.@"align",
507548 .segment_id = match.seg,
508549 .section_id = match.sect,
509550 };
src/link/MachO/Zld.zig+32-19
......@@ -139,47 +139,60 @@ const TlvOffset = struct {
139139
140140pub const TextBlock = struct {
141141 local_sym_index: u32,
142 aliases: std.ArrayList(u32),
143 references: std.ArrayList(u32),
142 aliases: ?[]u32 = null,
143 references: ?[]u32 = null,
144144 code: []u8,
145 relocs: std.ArrayList(*Relocation),
145 relocs: ?[]*Relocation = null,
146146 size: u64,
147147 alignment: u32,
148 segment_id: u16,
149 section_id: u16,
148 segment_id: u16 = 0,
149 section_id: u16 = 0,
150150 next: ?*TextBlock = null,
151151 prev: ?*TextBlock = null,
152152
153153 pub fn deinit(block: *TextBlock, allocator: *Allocator) void {
154 block.aliases.deinit();
155 block.references.deinit();
154 if (block.aliases) |aliases| {
155 allocator.free(aliases);
156 }
157 if (block.references) |references| {
158 allocator.free(references);
159 }
156160 for (block.relocs.items) |reloc| {
157161 allocator.destroy(reloc);
158162 }
159 block.relocs.deinit();
163 if (block.relocs) |relocs| {
164 allocator.free(relocs);
165 }
160166 allocator.free(code);
161167 }
162168
163 fn print(self: *const TextBlock, zld: *Zld) void {
164 if (self.prev) |prev| {
165 prev.print(zld);
166 }
167
169 pub fn print_this(self: *const TextBlock, zld: *Zld) void {
168170 log.warn("TextBlock", .{});
169171 log.warn(" | {}: '{s}'", .{ self.local_sym_index, zld.locals.items[self.local_sym_index].name });
170 log.warn(" | Aliases:", .{});
171 for (self.aliases.items) |index| {
172 log.warn(" | {}: '{s}'", .{ index, zld.locals.items[index].name });
172 if (self.aliases) |aliases| {
173 log.warn(" | Aliases:", .{});
174 for (aliases) |index| {
175 log.warn(" | {}: '{s}'", .{ index, zld.locals.items[index].name });
176 }
173177 }
174 log.warn(" | References:", .{});
175 for (self.references.items) |index| {
176 log.warn(" | {}: '{s}'", .{ index, zld.locals.items[index].name });
178 if (self.references) |references| {
179 log.warn(" | References:", .{});
180 for (references) |index| {
181 log.warn(" | {}: '{s}'", .{ index, zld.locals.items[index].name });
182 }
177183 }
178184 log.warn(" | size = {}", .{self.size});
179185 log.warn(" | align = {}", .{self.alignment});
180186 log.warn(" | segment_id = {}", .{self.segment_id});
181187 log.warn(" | section_id = {}", .{self.section_id});
182188 }
189
190 pub fn print(self: *const TextBlock, zld: *Zld) void {
191 if (self.prev) |prev| {
192 prev.print(zld);
193 }
194 self.print_this(zld);
195 }
183196};
184197
185198/// Default path to dyld