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 {...@@ -276,11 +276,11 @@ const NlistWithIndex = struct {
276 nlist: macho.nlist_64,276 nlist: macho.nlist_64,
277 index: u32,277 index: u32,
278278
279 pub fn cmp(_: void, lhs: @This(), rhs: @This()) bool {279 fn lessThan(_: void, lhs: @This(), rhs: @This()) bool {
280 return lhs.nlist.n_value < rhs.nlist.n_value;280 return lhs.nlist.n_value < rhs.nlist.n_value;
281 }281 }
282282
283 fn filterNlistsInSection(symbols: []@This(), sect_id: u8) []@This() {283 fn filterInSection(symbols: []@This(), sect_id: u8) []@This() {
284 var start: usize = 0;284 var start: usize = 0;
285 var end: usize = symbols.len;285 var end: usize = symbols.len;
286286
...@@ -327,19 +327,111 @@ fn filterRelocs(relocs: []macho.relocation_info, start: u64, end: u64) []macho.r...@@ -327,19 +327,111 @@ fn filterRelocs(relocs: []macho.relocation_info, start: u64, end: u64) []macho.r
327 return relocs[start_id..end_id];327 return relocs[start_id..end_id];
328}328}
329329
330const SeniorityContext = struct {330const TextBlockParser = struct {
331 allocator: *Allocator,
332 section: macho.section_64,
333 code: []u8,
334 object: *Object,
331 zld: *Zld,335 zld: *Zld,
332};336 nlists: []NlistWithIndex,
333fn cmpSymBySeniority(context: SeniorityContext, lhs: u32, rhs: u32) bool {337 index: u32 = 0,
334 const lreg = context.zld.locals.items[lhs].payload.regular;338
335 const rreg = context.zld.locals.items[rhs].payload.regular;339 fn peek(self: *TextBlockParser) ?NlistWithIndex {
336340 return if (self.index + 1 < self.nlists.len) self.nlists[self.index + 1] else null;
337 return switch (rreg.linkage) {341 }
338 .global => true,342
339 .linkage_unit => lreg.linkage == .translation_unit,343 const SeniorityContext = struct {
340 else => false,344 zld: *Zld,
341 };345 };
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
344pub fn parseTextBlocks(self: *Object, zld: *Zld) !?*TextBlock {436pub fn parseTextBlocks(self: *Object, zld: *Zld) !?*TextBlock {
345 const seg = self.load_commands.items[self.segment_cmd_index.?].Segment;437 const seg = self.load_commands.items[self.segment_cmd_index.?].Segment;
...@@ -361,7 +453,7 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !?*TextBlock {...@@ -361,7 +453,7 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !?*TextBlock {
361 });453 });
362 }454 }
363455
364 std.sort.sort(NlistWithIndex, sorted_nlists.items, {}, NlistWithIndex.cmp);456 std.sort.sort(NlistWithIndex, sorted_nlists.items, {}, NlistWithIndex.lessThan);
365457
366 var last_block: ?*TextBlock = null;458 var last_block: ?*TextBlock = null;
367459
...@@ -385,53 +477,26 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !?*TextBlock {...@@ -385,53 +477,26 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !?*TextBlock {
385 // Is there any padding between symbols within the section?477 // Is there any padding between symbols within the section?
386 const is_padded = self.header.?.flags & macho.MH_SUBSECTIONS_VIA_SYMBOLS != 0;478 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
391 next: {480 next: {
392 if (is_padded) blocks: {481 if (is_padded) blocks: {
393 const filtered_nlists = NlistWithIndex.filterNlistsInSection(482 const filtered_nlists = NlistWithIndex.filterInSection(
394 sorted_nlists.items,483 sorted_nlists.items,
395 @intCast(u8, sect_id + 1),484 @intCast(u8, sect_id + 1),
396 );485 );
397486
398 if (filtered_nlists.len == 0) break :blocks;487 if (filtered_nlists.len == 0) break :blocks;
399488
400 var nlist_indices = std.ArrayList(u32).init(self.allocator);489 var parser = TextBlockParser{
401 defer nlist_indices.deinit();490 .allocator = self.allocator,
402491 .section = sect,
403 var i: u32 = 0;492 .code = code,
404 while (i < filtered_nlists.len) : (i += 1) {493 .object = self,
405 const curr = filtered_nlists[i];494 .zld = zld,
406 try nlist_indices.append(curr.index);495 .nlists = filtered_nlists,
407496 };
408 const next: ?NlistWithIndex = if (i + 1 < filtered_nlists.len)497
409 filtered_nlists[i + 1]498 while (try parser.next()) |block| {
410 else499 const sym = zld.locals.items[block.local_sym_index];
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];
435 if (sym.payload.regular.file) |file| {500 if (sym.payload.regular.file) |file| {
436 if (file != self) {501 if (file != self) {
437 log.warn("deduping definition of {s} in {s}", .{ sym.name, self.name.? });502 log.warn("deduping definition of {s} in {s}", .{ sym.name, self.name.? });
...@@ -439,27 +504,8 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !?*TextBlock {...@@ -439,27 +504,8 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !?*TextBlock {
439 }504 }
440 }505 }
441506
442 const start_addr = curr.nlist.n_value - sect.addr;507 block.segment_id = match.seg;
443 const end_addr = if (next) |n| n.nlist.n_value - sect.addr else sect.size;508 block.section_id = match.sect;
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);
463509
464 // TODO parse relocs510 // TODO parse relocs
465511
...@@ -468,8 +514,6 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !?*TextBlock {...@@ -468,8 +514,6 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !?*TextBlock {
468 block.prev = last;514 block.prev = last;
469 }515 }
470 last_block = block;516 last_block = block;
471
472 nlist_indices.clearRetainingCapacity();
473 }517 }
474518
475 break :next;519 break :next;
...@@ -498,12 +542,9 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !?*TextBlock {...@@ -498,12 +542,9 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !?*TextBlock {
498542
499 block.* = .{543 block.* = .{
500 .local_sym_index = local_sym_index,544 .local_sym_index = local_sym_index,
501 .aliases = std.ArrayList(u32).init(self.allocator),
502 .references = std.ArrayList(u32).init(self.allocator),
503 .code = code,545 .code = code,
504 .relocs = std.ArrayList(*Relocation).init(self.allocator),
505 .size = sect.size,546 .size = sect.size,
506 .alignment = alignment,547 .alignment = sect.@"align",
507 .segment_id = match.seg,548 .segment_id = match.seg,
508 .section_id = match.sect,549 .section_id = match.sect,
509 };550 };
src/link/MachO/Zld.zig+32-19
...@@ -139,47 +139,60 @@ const TlvOffset = struct {...@@ -139,47 +139,60 @@ const TlvOffset = struct {
139139
140pub const TextBlock = struct {140pub const TextBlock = struct {
141 local_sym_index: u32,141 local_sym_index: u32,
142 aliases: std.ArrayList(u32),142 aliases: ?[]u32 = null,
143 references: std.ArrayList(u32),143 references: ?[]u32 = null,
144 code: []u8,144 code: []u8,
145 relocs: std.ArrayList(*Relocation),145 relocs: ?[]*Relocation = null,
146 size: u64,146 size: u64,
147 alignment: u32,147 alignment: u32,
148 segment_id: u16,148 segment_id: u16 = 0,
149 section_id: u16,149 section_id: u16 = 0,
150 next: ?*TextBlock = null,150 next: ?*TextBlock = null,
151 prev: ?*TextBlock = null,151 prev: ?*TextBlock = null,
152152
153 pub fn deinit(block: *TextBlock, allocator: *Allocator) void {153 pub fn deinit(block: *TextBlock, allocator: *Allocator) void {
154 block.aliases.deinit();154 if (block.aliases) |aliases| {
155 block.references.deinit();155 allocator.free(aliases);
156 }
157 if (block.references) |references| {
158 allocator.free(references);
159 }
156 for (block.relocs.items) |reloc| {160 for (block.relocs.items) |reloc| {
157 allocator.destroy(reloc);161 allocator.destroy(reloc);
158 }162 }
159 block.relocs.deinit();163 if (block.relocs) |relocs| {
164 allocator.free(relocs);
165 }
160 allocator.free(code);166 allocator.free(code);
161 }167 }
162168
163 fn print(self: *const TextBlock, zld: *Zld) void {169 pub fn print_this(self: *const TextBlock, zld: *Zld) void {
164 if (self.prev) |prev| {
165 prev.print(zld);
166 }
167
168 log.warn("TextBlock", .{});170 log.warn("TextBlock", .{});
169 log.warn(" | {}: '{s}'", .{ self.local_sym_index, zld.locals.items[self.local_sym_index].name });171 log.warn(" | {}: '{s}'", .{ self.local_sym_index, zld.locals.items[self.local_sym_index].name });
170 log.warn(" | Aliases:", .{});172 if (self.aliases) |aliases| {
171 for (self.aliases.items) |index| {173 log.warn(" | Aliases:", .{});
172 log.warn(" | {}: '{s}'", .{ index, zld.locals.items[index].name });174 for (aliases) |index| {
175 log.warn(" | {}: '{s}'", .{ index, zld.locals.items[index].name });
176 }
173 }177 }
174 log.warn(" | References:", .{});178 if (self.references) |references| {
175 for (self.references.items) |index| {179 log.warn(" | References:", .{});
176 log.warn(" | {}: '{s}'", .{ index, zld.locals.items[index].name });180 for (references) |index| {
181 log.warn(" | {}: '{s}'", .{ index, zld.locals.items[index].name });
182 }
177 }183 }
178 log.warn(" | size = {}", .{self.size});184 log.warn(" | size = {}", .{self.size});
179 log.warn(" | align = {}", .{self.alignment});185 log.warn(" | align = {}", .{self.alignment});
180 log.warn(" | segment_id = {}", .{self.segment_id});186 log.warn(" | segment_id = {}", .{self.segment_id});
181 log.warn(" | section_id = {}", .{self.section_id});187 log.warn(" | section_id = {}", .{self.section_id});
182 }188 }
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 }
183};196};
184197
185/// Default path to dyld198/// Default path to dyld