| ... | ... | @@ -20,8 +20,6 @@ const Atom = @import("Atom.zig"); |
| 20 | 20 | const LoadCommand = commands.LoadCommand; |
| 21 | 21 | const MachO = @import("../MachO.zig"); |
| 22 | 22 | |
| 23 | | const TextBlock = Atom; |
| 24 | | |
| 25 | 23 | file: fs.File, |
| 26 | 24 | name: []const u8, |
| 27 | 25 | |
| ... | ... | @@ -57,7 +55,7 @@ tu_name: ?[]const u8 = null, |
| 57 | 55 | tu_comp_dir: ?[]const u8 = null, |
| 58 | 56 | mtime: ?u64 = null, |
| 59 | 57 | |
| 60 | | text_blocks: std.ArrayListUnmanaged(*TextBlock) = .{}, |
| 58 | atoms: std.ArrayListUnmanaged(*Atom) = .{}, |
| 61 | 59 | sections_as_symbols: std.AutoHashMapUnmanaged(u16, u32) = .{}, |
| 62 | 60 | |
| 63 | 61 | // TODO symbol mapping and its inverse can probably be simple arrays |
| ... | ... | @@ -137,7 +135,7 @@ pub fn deinit(self: *Object, allocator: *Allocator) void { |
| 137 | 135 | self.data_in_code_entries.deinit(allocator); |
| 138 | 136 | self.symtab.deinit(allocator); |
| 139 | 137 | self.strtab.deinit(allocator); |
| 140 | | self.text_blocks.deinit(allocator); |
| 138 | self.atoms.deinit(allocator); |
| 141 | 139 | self.sections_as_symbols.deinit(allocator); |
| 142 | 140 | self.symbol_mapping.deinit(allocator); |
| 143 | 141 | self.reverse_symbol_mapping.deinit(allocator); |
| ... | ... | @@ -322,14 +320,14 @@ const Context = struct { |
| 322 | 320 | parsed_atoms: *ParsedAtoms, |
| 323 | 321 | }; |
| 324 | 322 | |
| 325 | | const TextBlockParser = struct { |
| 323 | const AtomParser = struct { |
| 326 | 324 | section: macho.section_64, |
| 327 | 325 | code: []u8, |
| 328 | 326 | relocs: []macho.relocation_info, |
| 329 | 327 | nlists: []NlistWithIndex, |
| 330 | 328 | index: u32 = 0, |
| 331 | 329 | |
| 332 | | fn peek(self: TextBlockParser) ?NlistWithIndex { |
| 330 | fn peek(self: AtomParser) ?NlistWithIndex { |
| 333 | 331 | return if (self.index + 1 < self.nlists.len) self.nlists[self.index + 1] else null; |
| 334 | 332 | } |
| 335 | 333 | |
| ... | ... | @@ -343,7 +341,7 @@ const TextBlockParser = struct { |
| 343 | 341 | } |
| 344 | 342 | } |
| 345 | 343 | |
| 346 | | pub fn next(self: *TextBlockParser, context: Context) !?*TextBlock { |
| 344 | pub fn next(self: *AtomParser, context: Context) !?*Atom { |
| 347 | 345 | if (self.index == self.nlists.len) return null; |
| 348 | 346 | |
| 349 | 347 | var aliases = std.ArrayList(NlistWithIndex).init(context.allocator); |
| ... | ... | @@ -368,12 +366,12 @@ const TextBlockParser = struct { |
| 368 | 366 | } |
| 369 | 367 | |
| 370 | 368 | if (aliases.items.len > 1) { |
| 371 | | // Bubble-up senior symbol as the main link to the text block. |
| 369 | // Bubble-up senior symbol as the main link to the atom. |
| 372 | 370 | sort.sort( |
| 373 | 371 | NlistWithIndex, |
| 374 | 372 | aliases.items, |
| 375 | 373 | context, |
| 376 | | TextBlockParser.lessThanBySeniority, |
| 374 | AtomParser.lessThanBySeniority, |
| 377 | 375 | ); |
| 378 | 376 | } |
| 379 | 377 | |
| ... | ... | @@ -393,12 +391,12 @@ const TextBlockParser = struct { |
| 393 | 391 | else |
| 394 | 392 | max_align; |
| 395 | 393 | |
| 396 | | const stab: ?TextBlock.Stab = if (context.object.debug_info) |di| blk: { |
| 394 | const stab: ?Atom.Stab = if (context.object.debug_info) |di| blk: { |
| 397 | 395 | // TODO there has to be a better to handle this. |
| 398 | 396 | for (di.inner.func_list.items) |func| { |
| 399 | 397 | if (func.pc_range) |range| { |
| 400 | 398 | if (senior_nlist.nlist.n_value >= range.start and senior_nlist.nlist.n_value < range.end) { |
| 401 | | break :blk TextBlock.Stab{ |
| 399 | break :blk Atom.Stab{ |
| 402 | 400 | .function = range.end - range.start, |
| 403 | 401 | }; |
| 404 | 402 | } |
| ... | ... | @@ -409,25 +407,25 @@ const TextBlockParser = struct { |
| 409 | 407 | break :blk .static; |
| 410 | 408 | } else null; |
| 411 | 409 | |
| 412 | | const block = try context.macho_file.createEmptyAtom(senior_nlist.index, size, actual_align); |
| 413 | | block.stab = stab; |
| 410 | const atom = try context.macho_file.createEmptyAtom(senior_nlist.index, size, actual_align); |
| 411 | atom.stab = stab; |
| 414 | 412 | |
| 415 | 413 | const is_zerofill = blk: { |
| 416 | 414 | const section_type = commands.sectionType(self.section); |
| 417 | 415 | break :blk section_type == macho.S_ZEROFILL or section_type == macho.S_THREAD_LOCAL_ZEROFILL; |
| 418 | 416 | }; |
| 419 | 417 | if (!is_zerofill) { |
| 420 | | mem.copy(u8, block.code.items, code); |
| 418 | mem.copy(u8, atom.code.items, code); |
| 421 | 419 | } |
| 422 | 420 | |
| 423 | | try block.aliases.ensureTotalCapacity(context.allocator, aliases.items.len); |
| 421 | try atom.aliases.ensureTotalCapacity(context.allocator, aliases.items.len); |
| 424 | 422 | for (aliases.items) |alias| { |
| 425 | | block.aliases.appendAssumeCapacity(alias.index); |
| 423 | atom.aliases.appendAssumeCapacity(alias.index); |
| 426 | 424 | const sym = &context.macho_file.locals.items[alias.index]; |
| 427 | 425 | sym.n_sect = @intCast(u8, context.macho_file.section_ordinals.getIndex(context.match).? + 1); |
| 428 | 426 | } |
| 429 | 427 | |
| 430 | | try block.parseRelocs(self.relocs, .{ |
| 428 | try atom.parseRelocs(self.relocs, .{ |
| 431 | 429 | .base_addr = self.section.addr, |
| 432 | 430 | .base_offset = start_addr, |
| 433 | 431 | .allocator = context.allocator, |
| ... | ... | @@ -442,10 +440,10 @@ const TextBlockParser = struct { |
| 442 | 440 | senior_nlist.nlist.n_value, |
| 443 | 441 | senior_nlist.nlist.n_value + size, |
| 444 | 442 | ); |
| 445 | | try block.dices.ensureTotalCapacity(context.allocator, dices.len); |
| 443 | try atom.dices.ensureTotalCapacity(context.allocator, dices.len); |
| 446 | 444 | |
| 447 | 445 | for (dices) |dice| { |
| 448 | | block.dices.appendAssumeCapacity(.{ |
| 446 | atom.dices.appendAssumeCapacity(.{ |
| 449 | 447 | .offset = dice.offset - try math.cast(u32, senior_nlist.nlist.n_value), |
| 450 | 448 | .length = dice.length, |
| 451 | 449 | .kind = dice.kind, |
| ... | ... | @@ -455,13 +453,13 @@ const TextBlockParser = struct { |
| 455 | 453 | |
| 456 | 454 | self.index += 1; |
| 457 | 455 | |
| 458 | | return block; |
| 456 | return atom; |
| 459 | 457 | } |
| 460 | 458 | }; |
| 461 | 459 | |
| 462 | | pub const ParsedAtoms = std.AutoHashMap(MachO.MatchingSection, *TextBlock); |
| 460 | pub const ParsedAtoms = std.AutoHashMap(MachO.MatchingSection, *Atom); |
| 463 | 461 | |
| 464 | | pub fn parseTextBlocks( |
| 462 | pub fn parseIntoAtoms( |
| 465 | 463 | self: *Object, |
| 466 | 464 | allocator: *Allocator, |
| 467 | 465 | object_id: u16, |
| ... | ... | @@ -508,7 +506,7 @@ pub fn parseTextBlocks( |
| 508 | 506 | |
| 509 | 507 | for (seg.sections.items) |sect, id| { |
| 510 | 508 | const sect_id = @intCast(u8, id); |
| 511 | | log.debug("putting section '{s},{s}' as a TextBlock", .{ |
| 509 | log.debug("putting section '{s},{s}' as an Atom", .{ |
| 512 | 510 | segmentName(sect), |
| 513 | 511 | sectionName(sect), |
| 514 | 512 | }); |
| ... | ... | @@ -551,12 +549,12 @@ pub fn parseTextBlocks( |
| 551 | 549 | macho_file.has_stabs = macho_file.has_stabs or self.debug_info != null; |
| 552 | 550 | |
| 553 | 551 | next: { |
| 554 | | if (is_splittable) blocks: { |
| 555 | | if (filtered_nlists.len == 0) break :blocks; |
| 552 | if (is_splittable) atoms: { |
| 553 | if (filtered_nlists.len == 0) break :atoms; |
| 556 | 554 | |
| 557 | 555 | // If the first nlist does not match the start of the section, |
| 558 | 556 | // then we need to encapsulate the memory range [section start, first symbol) |
| 559 | | // as a temporary symbol and insert the matching TextBlock. |
| 557 | // as a temporary symbol and insert the matching Atom. |
| 560 | 558 | const first_nlist = filtered_nlists[0].nlist; |
| 561 | 559 | if (first_nlist.n_value > sect.addr) { |
| 562 | 560 | const sym_name = try std.fmt.allocPrint(allocator, "l_{s}_{s}_{s}", .{ |
| ... | ... | @@ -566,8 +564,8 @@ pub fn parseTextBlocks( |
| 566 | 564 | }); |
| 567 | 565 | defer allocator.free(sym_name); |
| 568 | 566 | |
| 569 | | const block_local_sym_index = self.sections_as_symbols.get(sect_id) orelse blk: { |
| 570 | | const block_local_sym_index = @intCast(u32, macho_file.locals.items.len); |
| 567 | const atom_local_sym_index = self.sections_as_symbols.get(sect_id) orelse blk: { |
| 568 | const atom_local_sym_index = @intCast(u32, macho_file.locals.items.len); |
| 571 | 569 | try macho_file.locals.append(allocator, .{ |
| 572 | 570 | .n_strx = try macho_file.makeString(sym_name), |
| 573 | 571 | .n_type = macho.N_SECT, |
| ... | ... | @@ -575,22 +573,22 @@ pub fn parseTextBlocks( |
| 575 | 573 | .n_desc = 0, |
| 576 | 574 | .n_value = 0, |
| 577 | 575 | }); |
| 578 | | try self.sections_as_symbols.putNoClobber(allocator, sect_id, block_local_sym_index); |
| 579 | | break :blk block_local_sym_index; |
| 576 | try self.sections_as_symbols.putNoClobber(allocator, sect_id, atom_local_sym_index); |
| 577 | break :blk atom_local_sym_index; |
| 580 | 578 | }; |
| 581 | | const block_code = code[0 .. first_nlist.n_value - sect.addr]; |
| 582 | | const block_size = block_code.len; |
| 583 | | const block = try macho_file.createEmptyAtom(block_local_sym_index, block_size, sect.@"align"); |
| 579 | const atom_code = code[0 .. first_nlist.n_value - sect.addr]; |
| 580 | const atom_size = atom_code.len; |
| 581 | const atom = try macho_file.createEmptyAtom(atom_local_sym_index, atom_size, sect.@"align"); |
| 584 | 582 | |
| 585 | 583 | const is_zerofill = blk: { |
| 586 | 584 | const section_type = commands.sectionType(sect); |
| 587 | 585 | break :blk section_type == macho.S_ZEROFILL or section_type == macho.S_THREAD_LOCAL_ZEROFILL; |
| 588 | 586 | }; |
| 589 | 587 | if (!is_zerofill) { |
| 590 | | mem.copy(u8, block.code.items, block_code); |
| 588 | mem.copy(u8, atom.code.items, atom_code); |
| 591 | 589 | } |
| 592 | 590 | |
| 593 | | try block.parseRelocs(relocs, .{ |
| 591 | try atom.parseRelocs(relocs, .{ |
| 594 | 592 | .base_addr = sect.addr, |
| 595 | 593 | .base_offset = 0, |
| 596 | 594 | .allocator = allocator, |
| ... | ... | @@ -600,11 +598,11 @@ pub fn parseTextBlocks( |
| 600 | 598 | }); |
| 601 | 599 | |
| 602 | 600 | if (macho_file.has_dices) { |
| 603 | | const dices = filterDice(self.data_in_code_entries.items, sect.addr, sect.addr + block_size); |
| 604 | | try block.dices.ensureTotalCapacity(allocator, dices.len); |
| 601 | const dices = filterDice(self.data_in_code_entries.items, sect.addr, sect.addr + atom_size); |
| 602 | try atom.dices.ensureTotalCapacity(allocator, dices.len); |
| 605 | 603 | |
| 606 | 604 | for (dices) |dice| { |
| 607 | | block.dices.appendAssumeCapacity(.{ |
| 605 | atom.dices.appendAssumeCapacity(.{ |
| 608 | 606 | .offset = dice.offset - try math.cast(u32, sect.addr), |
| 609 | 607 | .length = dice.length, |
| 610 | 608 | .kind = dice.kind, |
| ... | ... | @@ -613,16 +611,16 @@ pub fn parseTextBlocks( |
| 613 | 611 | } |
| 614 | 612 | |
| 615 | 613 | if (parsed_atoms.getPtr(match)) |last| { |
| 616 | | last.*.next = block; |
| 617 | | block.prev = last.*; |
| 618 | | last.* = block; |
| 614 | last.*.next = atom; |
| 615 | atom.prev = last.*; |
| 616 | last.* = atom; |
| 619 | 617 | } else { |
| 620 | | try parsed_atoms.putNoClobber(match, block); |
| 618 | try parsed_atoms.putNoClobber(match, atom); |
| 621 | 619 | } |
| 622 | | try self.text_blocks.append(allocator, block); |
| 620 | try self.atoms.append(allocator, atom); |
| 623 | 621 | } |
| 624 | 622 | |
| 625 | | var parser = TextBlockParser{ |
| 623 | var parser = AtomParser{ |
| 626 | 624 | .section = sect, |
| 627 | 625 | .code = code, |
| 628 | 626 | .relocs = relocs, |
| ... | ... | @@ -635,10 +633,10 @@ pub fn parseTextBlocks( |
| 635 | 633 | .macho_file = macho_file, |
| 636 | 634 | .match = match, |
| 637 | 635 | .parsed_atoms = &parsed_atoms, |
| 638 | | })) |block| { |
| 639 | | const sym = macho_file.locals.items[block.local_sym_index]; |
| 636 | })) |atom| { |
| 637 | const sym = macho_file.locals.items[atom.local_sym_index]; |
| 640 | 638 | const is_ext = blk: { |
| 641 | | const orig_sym_id = self.reverse_symbol_mapping.get(block.local_sym_index) orelse unreachable; |
| 639 | const orig_sym_id = self.reverse_symbol_mapping.get(atom.local_sym_index) orelse unreachable; |
| 642 | 640 | break :blk MachO.symbolIsExt(self.symtab.items[orig_sym_id]); |
| 643 | 641 | }; |
| 644 | 642 | if (is_ext) { |
| ... | ... | @@ -662,26 +660,26 @@ pub fn parseTextBlocks( |
| 662 | 660 | // In x86_64 relocs, it can so happen that the compiler refers to the same |
| 663 | 661 | // atom by both the actual assigned symbol and the start of the section. In this |
| 664 | 662 | // case, we need to link the two together so add an alias. |
| 665 | | try block.aliases.append(allocator, alias); |
| 663 | try atom.aliases.append(allocator, alias); |
| 666 | 664 | } |
| 667 | 665 | } |
| 668 | 666 | |
| 669 | 667 | if (parsed_atoms.getPtr(match)) |last| { |
| 670 | | last.*.next = block; |
| 671 | | block.prev = last.*; |
| 672 | | last.* = block; |
| 668 | last.*.next = atom; |
| 669 | atom.prev = last.*; |
| 670 | last.* = atom; |
| 673 | 671 | } else { |
| 674 | | try parsed_atoms.putNoClobber(match, block); |
| 672 | try parsed_atoms.putNoClobber(match, atom); |
| 675 | 673 | } |
| 676 | | try self.text_blocks.append(allocator, block); |
| 674 | try self.atoms.append(allocator, atom); |
| 677 | 675 | } |
| 678 | 676 | |
| 679 | 677 | break :next; |
| 680 | 678 | } |
| 681 | 679 | |
| 682 | | // Since there is no symbol to refer to this block, we create |
| 680 | // Since there is no symbol to refer to this atom, we create |
| 683 | 681 | // a temp one, unless we already did that when working out the relocations |
| 684 | | // of other text blocks. |
| 682 | // of other atoms. |
| 685 | 683 | const sym_name = try std.fmt.allocPrint(allocator, "l_{s}_{s}_{s}", .{ |
| 686 | 684 | self.name, |
| 687 | 685 | segmentName(sect), |
| ... | ... | @@ -689,8 +687,8 @@ pub fn parseTextBlocks( |
| 689 | 687 | }); |
| 690 | 688 | defer allocator.free(sym_name); |
| 691 | 689 | |
| 692 | | const block_local_sym_index = self.sections_as_symbols.get(sect_id) orelse blk: { |
| 693 | | const block_local_sym_index = @intCast(u32, macho_file.locals.items.len); |
| 690 | const atom_local_sym_index = self.sections_as_symbols.get(sect_id) orelse blk: { |
| 691 | const atom_local_sym_index = @intCast(u32, macho_file.locals.items.len); |
| 694 | 692 | try macho_file.locals.append(allocator, .{ |
| 695 | 693 | .n_strx = try macho_file.makeString(sym_name), |
| 696 | 694 | .n_type = macho.N_SECT, |
| ... | ... | @@ -698,20 +696,20 @@ pub fn parseTextBlocks( |
| 698 | 696 | .n_desc = 0, |
| 699 | 697 | .n_value = 0, |
| 700 | 698 | }); |
| 701 | | try self.sections_as_symbols.putNoClobber(allocator, sect_id, block_local_sym_index); |
| 702 | | break :blk block_local_sym_index; |
| 699 | try self.sections_as_symbols.putNoClobber(allocator, sect_id, atom_local_sym_index); |
| 700 | break :blk atom_local_sym_index; |
| 703 | 701 | }; |
| 704 | | const block = try macho_file.createEmptyAtom(block_local_sym_index, sect.size, sect.@"align"); |
| 702 | const atom = try macho_file.createEmptyAtom(atom_local_sym_index, sect.size, sect.@"align"); |
| 705 | 703 | |
| 706 | 704 | const is_zerofill = blk: { |
| 707 | 705 | const section_type = commands.sectionType(sect); |
| 708 | 706 | break :blk section_type == macho.S_ZEROFILL or section_type == macho.S_THREAD_LOCAL_ZEROFILL; |
| 709 | 707 | }; |
| 710 | 708 | if (!is_zerofill) { |
| 711 | | mem.copy(u8, block.code.items, code); |
| 709 | mem.copy(u8, atom.code.items, code); |
| 712 | 710 | } |
| 713 | 711 | |
| 714 | | try block.parseRelocs(relocs, .{ |
| 712 | try atom.parseRelocs(relocs, .{ |
| 715 | 713 | .base_addr = sect.addr, |
| 716 | 714 | .base_offset = 0, |
| 717 | 715 | .allocator = allocator, |
| ... | ... | @@ -722,10 +720,10 @@ pub fn parseTextBlocks( |
| 722 | 720 | |
| 723 | 721 | if (macho_file.has_dices) { |
| 724 | 722 | const dices = filterDice(self.data_in_code_entries.items, sect.addr, sect.addr + sect.size); |
| 725 | | try block.dices.ensureTotalCapacity(allocator, dices.len); |
| 723 | try atom.dices.ensureTotalCapacity(allocator, dices.len); |
| 726 | 724 | |
| 727 | 725 | for (dices) |dice| { |
| 728 | | block.dices.appendAssumeCapacity(.{ |
| 726 | atom.dices.appendAssumeCapacity(.{ |
| 729 | 727 | .offset = dice.offset - try math.cast(u32, sect.addr), |
| 730 | 728 | .length = dice.length, |
| 731 | 729 | .kind = dice.kind, |
| ... | ... | @@ -733,12 +731,12 @@ pub fn parseTextBlocks( |
| 733 | 731 | } |
| 734 | 732 | } |
| 735 | 733 | |
| 736 | | // Since this is block gets a helper local temporary symbol that didn't exist |
| 734 | // Since this is atom gets a helper local temporary symbol that didn't exist |
| 737 | 735 | // in the object file which encompasses the entire section, we need traverse |
| 738 | 736 | // the filtered symbols and note which symbol is contained within so that |
| 739 | 737 | // we can properly allocate addresses down the line. |
| 740 | 738 | // While we're at it, we need to update segment,section mapping of each symbol too. |
| 741 | | try block.contained.ensureTotalCapacity(allocator, filtered_nlists.len); |
| 739 | try atom.contained.ensureTotalCapacity(allocator, filtered_nlists.len); |
| 742 | 740 | |
| 743 | 741 | for (filtered_nlists) |nlist_with_index| { |
| 744 | 742 | const nlist = nlist_with_index.nlist; |
| ... | ... | @@ -746,12 +744,12 @@ pub fn parseTextBlocks( |
| 746 | 744 | const local = &macho_file.locals.items[local_sym_index]; |
| 747 | 745 | local.n_sect = @intCast(u8, macho_file.section_ordinals.getIndex(match).? + 1); |
| 748 | 746 | |
| 749 | | const stab: ?TextBlock.Stab = if (self.debug_info) |di| blk: { |
| 747 | const stab: ?Atom.Stab = if (self.debug_info) |di| blk: { |
| 750 | 748 | // TODO there has to be a better to handle this. |
| 751 | 749 | for (di.inner.func_list.items) |func| { |
| 752 | 750 | if (func.pc_range) |range| { |
| 753 | 751 | if (nlist.n_value >= range.start and nlist.n_value < range.end) { |
| 754 | | break :blk TextBlock.Stab{ |
| 752 | break :blk Atom.Stab{ |
| 755 | 753 | .function = range.end - range.start, |
| 756 | 754 | }; |
| 757 | 755 | } |
| ... | ... | @@ -762,7 +760,7 @@ pub fn parseTextBlocks( |
| 762 | 760 | break :blk .static; |
| 763 | 761 | } else null; |
| 764 | 762 | |
| 765 | | block.contained.appendAssumeCapacity(.{ |
| 763 | atom.contained.appendAssumeCapacity(.{ |
| 766 | 764 | .local_sym_index = local_sym_index, |
| 767 | 765 | .offset = nlist.n_value - sect.addr, |
| 768 | 766 | .stab = stab, |
| ... | ... | @@ -770,13 +768,13 @@ pub fn parseTextBlocks( |
| 770 | 768 | } |
| 771 | 769 | |
| 772 | 770 | if (parsed_atoms.getPtr(match)) |last| { |
| 773 | | last.*.next = block; |
| 774 | | block.prev = last.*; |
| 775 | | last.* = block; |
| 771 | last.*.next = atom; |
| 772 | atom.prev = last.*; |
| 773 | last.* = atom; |
| 776 | 774 | } else { |
| 777 | | try parsed_atoms.putNoClobber(match, block); |
| 775 | try parsed_atoms.putNoClobber(match, atom); |
| 778 | 776 | } |
| 779 | | try self.text_blocks.append(allocator, block); |
| 777 | try self.atoms.append(allocator, atom); |
| 780 | 778 | } |
| 781 | 779 | } |
| 782 | 780 | |