| author | |
| committer | |
| log | 54a403d4ff9e20daf1843725012ae44ec828a833 |
| tree | 1c1679ee843c9caeb1986062a400cc42a645d560 |
| parent | 5a2bea29315158bc05fb4b09842bbb9ae0ddfada |
6 files changed, 340 insertions(+), 617 deletions(-)
CMakeLists.txt-1| ... | @@ -581,7 +581,6 @@ set(ZIG_STAGE2_SOURCES | ... | @@ -581,7 +581,6 @@ set(ZIG_STAGE2_SOURCES |
| 581 | "${CMAKE_SOURCE_DIR}/src/link/MachO/DebugSymbols.zig" | 581 | "${CMAKE_SOURCE_DIR}/src/link/MachO/DebugSymbols.zig" |
| 582 | "${CMAKE_SOURCE_DIR}/src/link/MachO/Dylib.zig" | 582 | "${CMAKE_SOURCE_DIR}/src/link/MachO/Dylib.zig" |
| 583 | "${CMAKE_SOURCE_DIR}/src/link/MachO/Object.zig" | 583 | "${CMAKE_SOURCE_DIR}/src/link/MachO/Object.zig" |
| 584 | "${CMAKE_SOURCE_DIR}/src/link/MachO/Symbol.zig" | ||
| 585 | "${CMAKE_SOURCE_DIR}/src/link/MachO/TextBlock.zig" | 584 | "${CMAKE_SOURCE_DIR}/src/link/MachO/TextBlock.zig" |
| 586 | "${CMAKE_SOURCE_DIR}/src/link/MachO/Trie.zig" | 585 | "${CMAKE_SOURCE_DIR}/src/link/MachO/Trie.zig" |
| 587 | "${CMAKE_SOURCE_DIR}/src/link/MachO/Zld.zig" | 586 | "${CMAKE_SOURCE_DIR}/src/link/MachO/Zld.zig" |
src/link/MachO/Dylib.zig+2-2| ... | @@ -12,8 +12,8 @@ const fat = @import("fat.zig"); | ... | @@ -12,8 +12,8 @@ const fat = @import("fat.zig"); |
| 12 | 12 | ||
| 13 | const Allocator = mem.Allocator; | 13 | const Allocator = mem.Allocator; |
| 14 | const Arch = std.Target.Cpu.Arch; | 14 | const Arch = std.Target.Cpu.Arch; |
| 15 | const Symbol = @import("Symbol.zig"); | ||
| 16 | const LibStub = @import("../tapi.zig").LibStub; | 15 | const LibStub = @import("../tapi.zig").LibStub; |
| 16 | const Zld = @import("Zld.zig"); | ||
| 17 | 17 | ||
| 18 | usingnamespace @import("commands.zig"); | 18 | usingnamespace @import("commands.zig"); |
| 19 | 19 | ||
| ... | @@ -324,7 +324,7 @@ fn parseSymbols(self: *Dylib) !void { | ... | @@ -324,7 +324,7 @@ fn parseSymbols(self: *Dylib) !void { |
| 324 | _ = try self.file.?.preadAll(strtab, symtab_cmd.stroff + self.library_offset); | 324 | _ = try self.file.?.preadAll(strtab, symtab_cmd.stroff + self.library_offset); |
| 325 | 325 | ||
| 326 | for (slice) |sym| { | 326 | for (slice) |sym| { |
| 327 | const add_to_symtab = Symbol.isExt(sym) and (Symbol.isSect(sym) or Symbol.isIndr(sym)); | 327 | const add_to_symtab = Zld.symbolIsExt(sym) and (Zld.symbolIsSect(sym) or Zld.symbolIsIndr(sym)); |
| 328 | 328 | ||
| 329 | if (!add_to_symtab) continue; | 329 | if (!add_to_symtab) continue; |
| 330 | 330 |
src/link/MachO/Object.zig+277-252| ... | @@ -9,13 +9,10 @@ const log = std.log.scoped(.object); | ... | @@ -9,13 +9,10 @@ const log = std.log.scoped(.object); |
| 9 | const macho = std.macho; | 9 | const macho = std.macho; |
| 10 | const math = std.math; | 10 | const math = std.math; |
| 11 | const mem = std.mem; | 11 | const mem = std.mem; |
| 12 | const reloc = @import("reloc.zig"); | ||
| 13 | const sort = std.sort; | 12 | const sort = std.sort; |
| 14 | 13 | ||
| 15 | const Allocator = mem.Allocator; | 14 | const Allocator = mem.Allocator; |
| 16 | const Arch = std.Target.Cpu.Arch; | 15 | const Arch = std.Target.Cpu.Arch; |
| 17 | const Relocation = reloc.Relocation; | ||
| 18 | const Symbol = @import("Symbol.zig"); | ||
| 19 | const TextBlock = @import("TextBlock.zig"); | 16 | const TextBlock = @import("TextBlock.zig"); |
| 20 | const Zld = @import("Zld.zig"); | 17 | const Zld = @import("Zld.zig"); |
| 21 | 18 | ||
| ... | @@ -57,6 +54,8 @@ tu_comp_dir: ?[]const u8 = null, | ... | @@ -57,6 +54,8 @@ tu_comp_dir: ?[]const u8 = null, |
| 57 | mtime: ?u64 = null, | 54 | mtime: ?u64 = null, |
| 58 | 55 | ||
| 59 | text_blocks: std.ArrayListUnmanaged(*TextBlock) = .{}, | 56 | text_blocks: std.ArrayListUnmanaged(*TextBlock) = .{}, |
| 57 | sections_as_symbols: std.AutoHashMapUnmanaged(u16, u32) = .{}, | ||
| 58 | symbol_mapping: std.AutoHashMapUnmanaged(u32, u32) = .{}, | ||
| 60 | 59 | ||
| 61 | const DebugInfo = struct { | 60 | const DebugInfo = struct { |
| 62 | inner: dwarf.DwarfInfo, | 61 | inner: dwarf.DwarfInfo, |
| ... | @@ -163,6 +162,8 @@ pub fn deinit(self: *Object) void { | ... | @@ -163,6 +162,8 @@ pub fn deinit(self: *Object) void { |
| 163 | self.symtab.deinit(self.allocator); | 162 | self.symtab.deinit(self.allocator); |
| 164 | self.strtab.deinit(self.allocator); | 163 | self.strtab.deinit(self.allocator); |
| 165 | self.text_blocks.deinit(self.allocator); | 164 | self.text_blocks.deinit(self.allocator); |
| 165 | self.sections_as_symbols.deinit(self.allocator); | ||
| 166 | self.symbol_mapping.deinit(self.allocator); | ||
| 166 | 167 | ||
| 167 | if (self.debug_info) |*db| { | 168 | if (self.debug_info) |*db| { |
| 168 | db.deinit(self.allocator); | 169 | db.deinit(self.allocator); |
| ... | @@ -372,20 +373,17 @@ const TextBlockParser = struct { | ... | @@ -372,20 +373,17 @@ const TextBlockParser = struct { |
| 372 | } | 373 | } |
| 373 | 374 | ||
| 374 | const SeniorityContext = struct { | 375 | const SeniorityContext = struct { |
| 375 | zld: *Zld, | 376 | object: *Object, |
| 376 | }; | 377 | }; |
| 377 | 378 | ||
| 378 | fn lessThanBySeniority(context: SeniorityContext, lhs: NlistWithIndex, rhs: NlistWithIndex) bool { | 379 | fn lessThanBySeniority(context: SeniorityContext, lhs: NlistWithIndex, rhs: NlistWithIndex) bool { |
| 379 | const lsym = context.zld.locals.items[lhs.index]; | 380 | if (!Zld.symbolIsExt(rhs.nlist)) { |
| 380 | const rsym = context.zld.locals.items[rhs.index]; | 381 | return Zld.symbolIsTemp(lhs.nlist, context.object.getString(lhs.nlist.n_strx)); |
| 381 | const lreg = lsym.payload.regular; | 382 | } else if (Zld.symbolIsPext(rhs.nlist) or Zld.symbolIsWeakDef(rhs.nlist)) { |
| 382 | const rreg = rsym.payload.regular; | 383 | return !Zld.symbolIsExt(lhs.nlist); |
| 383 | 384 | } else { | |
| 384 | return switch (rreg.linkage) { | 385 | return true; |
| 385 | .global => true, | 386 | } |
| 386 | .linkage_unit => lreg.linkage == .translation_unit, | ||
| 387 | else => lsym.isTemp(context.zld), | ||
| 388 | }; | ||
| 389 | } | 387 | } |
| 390 | 388 | ||
| 391 | pub fn next(self: *TextBlockParser) !?*TextBlock { | 389 | pub fn next(self: *TextBlockParser) !?*TextBlock { |
| ... | @@ -409,6 +407,7 @@ const TextBlockParser = struct { | ... | @@ -409,6 +407,7 @@ const TextBlockParser = struct { |
| 409 | } else null; | 407 | } else null; |
| 410 | 408 | ||
| 411 | for (aliases.items) |*nlist_with_index| { | 409 | for (aliases.items) |*nlist_with_index| { |
| 410 | nlist_with_index.index = self.symbol_mapping.get(nlist_with_index.index); | ||
| 412 | const sym = self.object.symbols.items[nlist_with_index.index]; | 411 | const sym = self.object.symbols.items[nlist_with_index.index]; |
| 413 | if (sym.payload != .regular) { | 412 | if (sym.payload != .regular) { |
| 414 | log.err("expected a regular symbol, found {s}", .{sym.payload}); | 413 | log.err("expected a regular symbol, found {s}", .{sym.payload}); |
| ... | @@ -424,7 +423,7 @@ const TextBlockParser = struct { | ... | @@ -424,7 +423,7 @@ const TextBlockParser = struct { |
| 424 | sort.sort( | 423 | sort.sort( |
| 425 | NlistWithIndex, | 424 | NlistWithIndex, |
| 426 | aliases.items, | 425 | aliases.items, |
| 427 | SeniorityContext{ .zld = self.zld }, | 426 | SeniorityContext{ .object = self.object }, |
| 428 | @This().lessThanBySeniority, | 427 | @This().lessThanBySeniority, |
| 429 | ); | 428 | ); |
| 430 | } | 429 | } |
| ... | @@ -515,7 +514,7 @@ const TextBlockParser = struct { | ... | @@ -515,7 +514,7 @@ const TextBlockParser = struct { |
| 515 | pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { | 514 | pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { |
| 516 | const seg = self.load_commands.items[self.segment_cmd_index.?].Segment; | 515 | const seg = self.load_commands.items[self.segment_cmd_index.?].Segment; |
| 517 | 516 | ||
| 518 | log.debug("analysing {s}", .{self.name.?}); | 517 | log.warn("analysing {s}", .{self.name.?}); |
| 519 | 518 | ||
| 520 | const dysymtab = self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab; | 519 | const dysymtab = self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab; |
| 521 | // We only care about defined symbols, so filter every other out. | 520 | // We only care about defined symbols, so filter every other out. |
| ... | @@ -536,14 +535,14 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { | ... | @@ -536,14 +535,14 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { |
| 536 | 535 | ||
| 537 | for (seg.sections.items) |sect, id| { | 536 | for (seg.sections.items) |sect, id| { |
| 538 | const sect_id = @intCast(u8, id); | 537 | const sect_id = @intCast(u8, id); |
| 539 | log.debug("putting section '{s},{s}' as a TextBlock", .{ | 538 | log.warn("putting section '{s},{s}' as a TextBlock", .{ |
| 540 | segmentName(sect), | 539 | segmentName(sect), |
| 541 | sectionName(sect), | 540 | sectionName(sect), |
| 542 | }); | 541 | }); |
| 543 | 542 | ||
| 544 | // Get matching segment/section in the final artifact. | 543 | // Get matching segment/section in the final artifact. |
| 545 | const match = (try zld.getMatchingSection(sect)) orelse { | 544 | const match = (try zld.getMatchingSection(sect)) orelse { |
| 546 | log.debug("unhandled section", .{}); | 545 | log.warn("unhandled section", .{}); |
| 547 | continue; | 546 | continue; |
| 548 | }; | 547 | }; |
| 549 | 548 | ||
| ... | @@ -577,200 +576,249 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { | ... | @@ -577,200 +576,249 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { |
| 577 | }; | 576 | }; |
| 578 | zld.has_stabs = zld.has_stabs or self.debug_info != null; | 577 | zld.has_stabs = zld.has_stabs or self.debug_info != null; |
| 579 | 578 | ||
| 580 | next: { | 579 | { |
| 581 | if (is_splittable) blocks: { | 580 | // next: { |
| 582 | if (filtered_nlists.len == 0) break :blocks; | 581 | // if (is_splittable) blocks: { |
| 583 | 582 | // if (filtered_nlists.len == 0) break :blocks; | |
| 584 | // If the first nlist does not match the start of the section, | 583 | |
| 585 | // then we need encapsulate the memory range [section start, first symbol) | 584 | // // If the first nlist does not match the start of the section, |
| 586 | // as a temporary symbol and insert the matching TextBlock. | 585 | // // then we need encapsulate the memory range [section start, first symbol) |
| 587 | const first_nlist = filtered_nlists[0].nlist; | 586 | // // as a temporary symbol and insert the matching TextBlock. |
| 588 | if (first_nlist.n_value > sect.addr) { | 587 | // const first_nlist = filtered_nlists[0].nlist; |
| 589 | const symbol = self.sections_as_symbols.get(sect_id) orelse symbol: { | 588 | // if (first_nlist.n_value > sect.addr) { |
| 590 | const name = try std.fmt.allocPrint(self.allocator, "l_{s}_{s}_{s}", .{ | 589 | // const symbol = self.sections_as_symbols.get(sect_id) orelse symbol: { |
| 591 | self.name.?, | 590 | // const name = try std.fmt.allocPrint(self.allocator, "l_{s}_{s}_{s}", .{ |
| 592 | segmentName(sect), | 591 | // self.name.?, |
| 593 | sectionName(sect), | 592 | // segmentName(sect), |
| 594 | }); | 593 | // sectionName(sect), |
| 595 | defer self.allocator.free(name); | 594 | // }); |
| 596 | const symbol = try zld.allocator.create(Symbol); | 595 | // defer self.allocator.free(name); |
| 597 | symbol.* = .{ | 596 | // const symbol = try zld.allocator.create(Symbol); |
| 598 | .strx = try zld.makeString(name), | 597 | // symbol.* = .{ |
| 599 | .payload = .{ .undef = .{} }, | 598 | // .strx = try zld.makeString(name), |
| 600 | }; | 599 | // .payload = .{ .undef = .{} }, |
| 601 | try self.sections_as_symbols.putNoClobber(self.allocator, sect_id, symbol); | 600 | // }; |
| 602 | break :symbol symbol; | 601 | // try self.sections_as_symbols.putNoClobber(self.allocator, sect_id, symbol); |
| 603 | }; | 602 | // break :symbol symbol; |
| 604 | 603 | // }; | |
| 605 | const local_sym_index = @intCast(u32, zld.locals.items.len); | 604 | |
| 606 | symbol.payload = .{ | 605 | // const local_sym_index = @intCast(u32, zld.locals.items.len); |
| 607 | .regular = .{ | 606 | // symbol.payload = .{ |
| 608 | .linkage = .translation_unit, | 607 | // .regular = .{ |
| 609 | .address = sect.addr, | 608 | // .linkage = .translation_unit, |
| 610 | .segment_id = match.seg, | 609 | // .address = sect.addr, |
| 611 | .section_id = match.sect, | 610 | // .segment_id = match.seg, |
| 612 | .file = self, | 611 | // .section_id = match.sect, |
| 613 | .local_sym_index = local_sym_index, | 612 | // .file = self, |
| 614 | }, | 613 | // .local_sym_index = local_sym_index, |
| 615 | }; | 614 | // }, |
| 616 | try zld.locals.append(zld.allocator, symbol); | 615 | // }; |
| 617 | 616 | // try zld.locals.append(zld.allocator, symbol); | |
| 618 | const block_code = code[0 .. first_nlist.n_value - sect.addr]; | 617 | |
| 619 | const block_size = block_code.len; | 618 | // const block_code = code[0 .. first_nlist.n_value - sect.addr]; |
| 620 | 619 | // const block_size = block_code.len; | |
| 621 | const block = try self.allocator.create(TextBlock); | 620 | |
| 622 | errdefer self.allocator.destroy(block); | 621 | // const block = try self.allocator.create(TextBlock); |
| 623 | 622 | // errdefer self.allocator.destroy(block); | |
| 624 | block.* = TextBlock.init(self.allocator); | 623 | |
| 625 | block.local_sym_index = local_sym_index; | 624 | // block.* = TextBlock.init(self.allocator); |
| 626 | block.code = try self.allocator.dupe(u8, block_code); | 625 | // block.local_sym_index = local_sym_index; |
| 627 | block.size = block_size; | 626 | // block.code = try self.allocator.dupe(u8, block_code); |
| 628 | block.alignment = sect.@"align"; | 627 | // block.size = block_size; |
| 629 | 628 | // block.alignment = sect.@"align"; | |
| 630 | const block_relocs = filterRelocs(relocs, 0, block_size); | 629 | |
| 631 | if (block_relocs.len > 0) { | 630 | // const block_relocs = filterRelocs(relocs, 0, block_size); |
| 632 | try self.parseRelocs(zld, block_relocs, block, 0); | 631 | // if (block_relocs.len > 0) { |
| 633 | } | 632 | // try self.parseRelocs(zld, block_relocs, block, 0); |
| 634 | 633 | // } | |
| 635 | if (zld.has_dices) { | 634 | |
| 636 | const dices = filterDice(self.data_in_code_entries.items, sect.addr, sect.addr + block_size); | 635 | // if (zld.has_dices) { |
| 637 | try block.dices.ensureTotalCapacity(dices.len); | 636 | // const dices = filterDice(self.data_in_code_entries.items, sect.addr, sect.addr + block_size); |
| 638 | 637 | // try block.dices.ensureTotalCapacity(dices.len); | |
| 639 | for (dices) |dice| { | 638 | |
| 640 | block.dices.appendAssumeCapacity(.{ | 639 | // for (dices) |dice| { |
| 641 | .offset = dice.offset - try math.cast(u32, sect.addr), | 640 | // block.dices.appendAssumeCapacity(.{ |
| 642 | .length = dice.length, | 641 | // .offset = dice.offset - try math.cast(u32, sect.addr), |
| 643 | .kind = dice.kind, | 642 | // .length = dice.length, |
| 644 | }); | 643 | // .kind = dice.kind, |
| 645 | } | 644 | // }); |
| 646 | } | 645 | // } |
| 647 | 646 | // } | |
| 648 | // Update target section's metadata | 647 | |
| 649 | // TODO should we update segment's size here too? | 648 | // // Update target section's metadata |
| 650 | // How does it tie with incremental space allocs? | 649 | // // TODO should we update segment's size here too? |
| 651 | const tseg = &zld.load_commands.items[match.seg].Segment; | 650 | // // How does it tie with incremental space allocs? |
| 652 | const tsect = &tseg.sections.items[match.sect]; | 651 | // const tseg = &zld.load_commands.items[match.seg].Segment; |
| 653 | const new_alignment = math.max(tsect.@"align", block.alignment); | 652 | // const tsect = &tseg.sections.items[match.sect]; |
| 654 | const new_alignment_pow_2 = try math.powi(u32, 2, new_alignment); | 653 | // const new_alignment = math.max(tsect.@"align", block.alignment); |
| 655 | const new_size = mem.alignForwardGeneric(u64, tsect.size, new_alignment_pow_2) + block.size; | 654 | // const new_alignment_pow_2 = try math.powi(u32, 2, new_alignment); |
| 656 | tsect.size = new_size; | 655 | // const new_size = mem.alignForwardGeneric(u64, tsect.size, new_alignment_pow_2) + block.size; |
| 657 | tsect.@"align" = new_alignment; | 656 | // tsect.size = new_size; |
| 658 | 657 | // tsect.@"align" = new_alignment; | |
| 659 | if (zld.blocks.getPtr(match)) |last| { | 658 | |
| 660 | last.*.next = block; | 659 | // if (zld.blocks.getPtr(match)) |last| { |
| 661 | block.prev = last.*; | 660 | // last.*.next = block; |
| 662 | last.* = block; | 661 | // block.prev = last.*; |
| 663 | } else { | 662 | // last.* = block; |
| 664 | try zld.blocks.putNoClobber(zld.allocator, match, block); | 663 | // } else { |
| 665 | } | 664 | // try zld.blocks.putNoClobber(zld.allocator, match, block); |
| 666 | 665 | // } | |
| 667 | try self.text_blocks.append(self.allocator, block); | 666 | |
| 668 | } | 667 | // try self.text_blocks.append(self.allocator, block); |
| 669 | 668 | // } | |
| 670 | var parser = TextBlockParser{ | 669 | |
| 671 | .allocator = self.allocator, | 670 | // var parser = TextBlockParser{ |
| 672 | .section = sect, | 671 | // .allocator = self.allocator, |
| 673 | .code = code, | 672 | // .section = sect, |
| 674 | .relocs = relocs, | 673 | // .code = code, |
| 675 | .object = self, | 674 | // .relocs = relocs, |
| 676 | .zld = zld, | 675 | // .object = self, |
| 677 | .nlists = filtered_nlists, | 676 | // .zld = zld, |
| 678 | .match = match, | 677 | // .nlists = filtered_nlists, |
| 679 | }; | 678 | // .match = match, |
| 680 | 679 | // }; | |
| 681 | while (try parser.next()) |block| { | 680 | |
| 682 | const sym = zld.locals.items[block.local_sym_index]; | 681 | // while (try parser.next()) |block| { |
| 683 | const reg = &sym.payload.regular; | 682 | // const sym = zld.locals.items[block.local_sym_index]; |
| 684 | if (reg.file) |file| { | 683 | // const reg = &sym.payload.regular; |
| 685 | if (file != self) { | 684 | // if (reg.file) |file| { |
| 686 | log.debug("deduping definition of {s} in {s}", .{ zld.getString(sym.strx), self.name.? }); | 685 | // if (file != self) { |
| 687 | block.deinit(); | 686 | // log.debug("deduping definition of {s} in {s}", .{ zld.getString(sym.strx), self.name.? }); |
| 688 | self.allocator.destroy(block); | 687 | // block.deinit(); |
| 689 | continue; | 688 | // self.allocator.destroy(block); |
| 690 | } | 689 | // continue; |
| 691 | } | 690 | // } |
| 692 | 691 | // } | |
| 693 | if (reg.address == sect.addr) { | 692 | |
| 694 | if (self.sections_as_symbols.get(sect_id)) |alias| { | 693 | // if (reg.address == sect.addr) { |
| 695 | // Add alias. | 694 | // if (self.sections_as_symbols.get(sect_id)) |alias| { |
| 696 | const local_sym_index = @intCast(u32, zld.locals.items.len); | 695 | // // Add alias. |
| 697 | const reg_alias = &alias.payload.regular; | 696 | // const local_sym_index = @intCast(u32, zld.locals.items.len); |
| 698 | reg_alias.segment_id = match.seg; | 697 | // const reg_alias = &alias.payload.regular; |
| 699 | reg_alias.section_id = match.sect; | 698 | // reg_alias.segment_id = match.seg; |
| 700 | reg_alias.local_sym_index = local_sym_index; | 699 | // reg_alias.section_id = match.sect; |
| 701 | try block.aliases.append(local_sym_index); | 700 | // reg_alias.local_sym_index = local_sym_index; |
| 702 | try zld.locals.append(zld.allocator, alias); | 701 | // try block.aliases.append(local_sym_index); |
| 703 | } | 702 | // try zld.locals.append(zld.allocator, alias); |
| 704 | } | 703 | // } |
| 705 | 704 | // } | |
| 706 | // Update target section's metadata | 705 | |
| 707 | // TODO should we update segment's size here too? | 706 | // // Update target section's metadata |
| 708 | // How does it tie with incremental space allocs? | 707 | // // TODO should we update segment's size here too? |
| 709 | const tseg = &zld.load_commands.items[match.seg].Segment; | 708 | // // How does it tie with incremental space allocs? |
| 710 | const tsect = &tseg.sections.items[match.sect]; | 709 | // const tseg = &zld.load_commands.items[match.seg].Segment; |
| 711 | const new_alignment = math.max(tsect.@"align", block.alignment); | 710 | // const tsect = &tseg.sections.items[match.sect]; |
| 712 | const new_alignment_pow_2 = try math.powi(u32, 2, new_alignment); | 711 | // const new_alignment = math.max(tsect.@"align", block.alignment); |
| 713 | const new_size = mem.alignForwardGeneric(u64, tsect.size, new_alignment_pow_2) + block.size; | 712 | // const new_alignment_pow_2 = try math.powi(u32, 2, new_alignment); |
| 714 | tsect.size = new_size; | 713 | // const new_size = mem.alignForwardGeneric(u64, tsect.size, new_alignment_pow_2) + block.size; |
| 715 | tsect.@"align" = new_alignment; | 714 | // tsect.size = new_size; |
| 716 | 715 | // tsect.@"align" = new_alignment; | |
| 717 | if (zld.blocks.getPtr(match)) |last| { | 716 | |
| 718 | last.*.next = block; | 717 | // if (zld.blocks.getPtr(match)) |last| { |
| 719 | block.prev = last.*; | 718 | // last.*.next = block; |
| 720 | last.* = block; | 719 | // block.prev = last.*; |
| 721 | } else { | 720 | // last.* = block; |
| 722 | try zld.blocks.putNoClobber(zld.allocator, match, block); | 721 | // } else { |
| 723 | } | 722 | // try zld.blocks.putNoClobber(zld.allocator, match, block); |
| 724 | 723 | // } | |
| 725 | try self.text_blocks.append(self.allocator, block); | 724 | |
| 726 | } | 725 | // try self.text_blocks.append(self.allocator, block); |
| 727 | 726 | // } | |
| 728 | break :next; | 727 | |
| 729 | } | 728 | // break :next; |
| 729 | // } | ||
| 730 | 730 | ||
| 731 | // Since there is no symbol to refer to this block, we create | 731 | // Since there is no symbol to refer to this block, we create |
| 732 | // a temp one, unless we already did that when working out the relocations | 732 | // a temp one, unless we already did that when working out the relocations |
| 733 | // of other text blocks. | 733 | // of other text blocks. |
| 734 | const symbol = self.sections_as_symbols.get(sect_id) orelse symbol: { | 734 | const block_local_sym_index = @intCast(u32, zld.locals.items.len); |
| 735 | const name = try std.fmt.allocPrint(self.allocator, "l_{s}_{s}_{s}", .{ | 735 | const sym_name = try std.fmt.allocPrint(self.allocator, "l_{s}_{s}_{s}", .{ |
| 736 | self.name.?, | 736 | self.name.?, |
| 737 | segmentName(sect), | 737 | segmentName(sect), |
| 738 | sectionName(sect), | 738 | sectionName(sect), |
| 739 | }); | 739 | }); |
| 740 | defer self.allocator.free(name); | 740 | defer self.allocator.free(sym_name); |
| 741 | const symbol = try zld.allocator.create(Symbol); | 741 | try zld.locals.append(zld.allocator, .{ |
| 742 | symbol.* = .{ | 742 | .n_strx = try zld.makeString(sym_name), |
| 743 | .strx = try zld.makeString(name), | 743 | .n_type = macho.N_SECT, |
| 744 | .payload = .{ .undef = .{} }, | 744 | .n_sect = zld.sectionId(match), |
| 745 | }; | 745 | .n_desc = 0, |
| 746 | try self.sections_as_symbols.putNoClobber(self.allocator, sect_id, symbol); | 746 | .n_value = sect.addr, |
| 747 | break :symbol symbol; | 747 | }); |
| 748 | }; | 748 | const block_local = &zld.locals.items[block_local_sym_index]; |
| 749 | 749 | block_local.n_sect = zld.sectionId(match); | |
| 750 | const local_sym_index = @intCast(u32, zld.locals.items.len); | ||
| 751 | symbol.payload = .{ | ||
| 752 | .regular = .{ | ||
| 753 | .linkage = .translation_unit, | ||
| 754 | .address = sect.addr, | ||
| 755 | .segment_id = match.seg, | ||
| 756 | .section_id = match.sect, | ||
| 757 | .file = self, | ||
| 758 | .local_sym_index = local_sym_index, | ||
| 759 | }, | ||
| 760 | }; | ||
| 761 | try zld.locals.append(zld.allocator, symbol); | ||
| 762 | 750 | ||
| 763 | const block = try self.allocator.create(TextBlock); | 751 | const block = try self.allocator.create(TextBlock); |
| 764 | errdefer self.allocator.destroy(block); | 752 | errdefer self.allocator.destroy(block); |
| 765 | 753 | ||
| 766 | block.* = TextBlock.init(self.allocator); | 754 | block.* = TextBlock.init(self.allocator); |
| 767 | block.local_sym_index = local_sym_index; | 755 | block.local_sym_index = block_local_sym_index; |
| 768 | block.code = try self.allocator.dupe(u8, code); | 756 | block.code = try self.allocator.dupe(u8, code); |
| 769 | block.size = sect.size; | 757 | block.size = sect.size; |
| 770 | block.alignment = sect.@"align"; | 758 | block.alignment = sect.@"align"; |
| 771 | 759 | ||
| 772 | if (relocs.len > 0) { | 760 | try block.relocs.ensureTotalCapacity(relocs.len); |
| 773 | try self.parseRelocs(zld, relocs, block, 0); | 761 | for (relocs) |rel| { |
| 762 | const out_rel: TextBlock.Relocation = outer: { | ||
| 763 | if (rel.r_extern == 0) { | ||
| 764 | const rel_sect_id = @intCast(u16, rel.r_symbolnum - 1); | ||
| 765 | const sect_sym_index = self.sections_as_symbols.get(rel_sect_id) orelse blk: { | ||
| 766 | const sect_sym_index = @intCast(u32, zld.locals.items.len); | ||
| 767 | const sect_sym_name = try std.fmt.allocPrint(self.allocator, "l_{s}_{s}_{s}", .{ | ||
| 768 | self.name.?, | ||
| 769 | segmentName(sect), | ||
| 770 | sectionName(sect), | ||
| 771 | }); | ||
| 772 | defer self.allocator.free(sect_sym_name); | ||
| 773 | try zld.locals.append(zld.allocator, .{ | ||
| 774 | .n_strx = try zld.makeString(sect_sym_name), | ||
| 775 | .n_type = macho.N_SECT, | ||
| 776 | .n_sect = 0, | ||
| 777 | .n_desc = 0, | ||
| 778 | .n_value = 0, | ||
| 779 | }); | ||
| 780 | try self.sections_as_symbols.putNoClobber(self.allocator, rel_sect_id, sect_sym_index); | ||
| 781 | break :blk sect_sym_index; | ||
| 782 | }; | ||
| 783 | break :outer .{ | ||
| 784 | .inner = rel, | ||
| 785 | .where = .local, | ||
| 786 | .where_index = sect_sym_index, | ||
| 787 | }; | ||
| 788 | } | ||
| 789 | |||
| 790 | const rel_sym = self.symtab.items[rel.r_symbolnum]; | ||
| 791 | const rel_sym_name = self.getString(rel_sym.n_strx); | ||
| 792 | |||
| 793 | if (Zld.symbolIsSect(rel_sym) and !Zld.symbolIsExt(rel_sym)) { | ||
| 794 | const where_index = self.symbol_mapping.get(rel.r_symbolnum) orelse unreachable; | ||
| 795 | break :outer .{ | ||
| 796 | .inner = rel, | ||
| 797 | .where = .local, | ||
| 798 | .where_index = where_index, | ||
| 799 | }; | ||
| 800 | } | ||
| 801 | |||
| 802 | const resolv = zld.symbol_resolver.get(rel_sym_name) orelse unreachable; | ||
| 803 | switch (resolv.where) { | ||
| 804 | .global => { | ||
| 805 | break :outer .{ | ||
| 806 | .inner = rel, | ||
| 807 | .where = .local, | ||
| 808 | .where_index = resolv.local_sym_index, | ||
| 809 | }; | ||
| 810 | }, | ||
| 811 | .import => { | ||
| 812 | break :outer .{ | ||
| 813 | .inner = rel, | ||
| 814 | .where = .import, | ||
| 815 | .where_index = resolv.where_index, | ||
| 816 | }; | ||
| 817 | }, | ||
| 818 | else => unreachable, | ||
| 819 | } | ||
| 820 | }; | ||
| 821 | block.relocs.appendAssumeCapacity(out_rel); | ||
| 774 | } | 822 | } |
| 775 | 823 | ||
| 776 | if (zld.has_dices) { | 824 | if (zld.has_dices) { |
| ... | @@ -791,44 +839,41 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { | ... | @@ -791,44 +839,41 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { |
| 791 | // the filtered symbols and note which symbol is contained within so that | 839 | // the filtered symbols and note which symbol is contained within so that |
| 792 | // we can properly allocate addresses down the line. | 840 | // we can properly allocate addresses down the line. |
| 793 | // While we're at it, we need to update segment,section mapping of each symbol too. | 841 | // While we're at it, we need to update segment,section mapping of each symbol too. |
| 794 | if (filtered_nlists.len > 0) { | 842 | var contained = std.ArrayList(TextBlock.SymbolAtOffset).init(self.allocator); |
| 795 | var contained = std.ArrayList(TextBlock.SymbolAtOffset).init(self.allocator); | 843 | defer contained.deinit(); |
| 796 | defer contained.deinit(); | 844 | try contained.ensureTotalCapacity(filtered_nlists.len); |
| 797 | try contained.ensureTotalCapacity(filtered_nlists.len); | 845 | |
| 798 | 846 | for (filtered_nlists) |nlist_with_index| { | |
| 799 | for (filtered_nlists) |nlist_with_index| { | 847 | const nlist = nlist_with_index.nlist; |
| 800 | const sym = self.symbols.items[nlist_with_index.index]; | 848 | const local_sym_index = self.symbol_mapping.get(nlist_with_index.index) orelse unreachable; |
| 801 | assert(sym.payload == .regular); | 849 | const local = &zld.locals.items[local_sym_index]; |
| 802 | const reg = &sym.payload.regular; | 850 | local.n_sect = zld.sectionId(match); |
| 803 | 851 | ||
| 804 | reg.segment_id = match.seg; | 852 | const stab: ?TextBlock.Stab = if (self.debug_info) |di| blk: { |
| 805 | reg.section_id = match.sect; | 853 | // TODO there has to be a better to handle this. |
| 806 | 854 | for (di.inner.func_list.items) |func| { | |
| 807 | const stab: ?TextBlock.Stab = if (self.debug_info) |di| blk: { | 855 | if (func.pc_range) |range| { |
| 808 | // TODO there has to be a better to handle this. | 856 | if (nlist.n_value >= range.start and nlist.n_value < range.end) { |
| 809 | for (di.inner.func_list.items) |func| { | 857 | break :blk TextBlock.Stab{ |
| 810 | if (func.pc_range) |range| { | 858 | .function = range.end - range.start, |
| 811 | if (reg.address >= range.start and reg.address < range.end) { | 859 | }; |
| 812 | break :blk TextBlock.Stab{ | ||
| 813 | .function = range.end - range.start, | ||
| 814 | }; | ||
| 815 | } | ||
| 816 | } | 860 | } |
| 817 | } | 861 | } |
| 818 | if (zld.globals.contains(zld.getString(sym.strx))) break :blk .global; | 862 | } |
| 819 | break :blk .static; | 863 | // TODO |
| 820 | } else null; | 864 | // if (zld.globals.contains(zld.getString(sym.strx))) break :blk .global; |
| 821 | 865 | break :blk .static; | |
| 822 | contained.appendAssumeCapacity(.{ | 866 | } else null; |
| 823 | .local_sym_index = reg.local_sym_index, | ||
| 824 | .offset = nlist_with_index.nlist.n_value - sect.addr, | ||
| 825 | .stab = stab, | ||
| 826 | }); | ||
| 827 | } | ||
| 828 | 867 | ||
| 829 | block.contained = contained.toOwnedSlice(); | 868 | contained.appendAssumeCapacity(.{ |
| 869 | .local_sym_index = local_sym_index, | ||
| 870 | .offset = nlist.n_value - sect.addr, | ||
| 871 | .stab = stab, | ||
| 872 | }); | ||
| 830 | } | 873 | } |
| 831 | 874 | ||
| 875 | block.contained = contained.toOwnedSlice(); | ||
| 876 | |||
| 832 | // Update target section's metadata | 877 | // Update target section's metadata |
| 833 | // TODO should we update segment's size here too? | 878 | // TODO should we update segment's size here too? |
| 834 | // How does it tie with incremental space allocs? | 879 | // How does it tie with incremental space allocs? |
| ... | @@ -853,26 +898,6 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { | ... | @@ -853,26 +898,6 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { |
| 853 | } | 898 | } |
| 854 | } | 899 | } |
| 855 | 900 | ||
| 856 | fn parseRelocs( | ||
| 857 | self: *Object, | ||
| 858 | zld: *Zld, | ||
| 859 | relocs: []const macho.relocation_info, | ||
| 860 | block: *TextBlock, | ||
| 861 | base_addr: u64, | ||
| 862 | ) !void { | ||
| 863 | var it = reloc.RelocIterator{ | ||
| 864 | .buffer = relocs, | ||
| 865 | }; | ||
| 866 | var parser = reloc.Parser{ | ||
| 867 | .object = self, | ||
| 868 | .zld = zld, | ||
| 869 | .it = &it, | ||
| 870 | .block = block, | ||
| 871 | .base_addr = base_addr, | ||
| 872 | }; | ||
| 873 | try parser.parse(); | ||
| 874 | } | ||
| 875 | |||
| 876 | pub fn symbolFromReloc(self: *Object, zld: *Zld, rel: macho.relocation_info) !*Symbol { | 901 | pub fn symbolFromReloc(self: *Object, zld: *Zld, rel: macho.relocation_info) !*Symbol { |
| 877 | const symbol = blk: { | 902 | const symbol = blk: { |
| 878 | if (rel.r_extern == 1) { | 903 | if (rel.r_extern == 1) { |
src/link/MachO/Symbol.zig deleted-285| ... | @@ -1,285 +0,0 @@ | ||
| 1 | const Symbol = @This(); | ||
| 2 | |||
| 3 | const std = @import("std"); | ||
| 4 | const assert = std.debug.assert; | ||
| 5 | const commands = @import("commands.zig"); | ||
| 6 | const macho = std.macho; | ||
| 7 | const mem = std.mem; | ||
| 8 | |||
| 9 | const Allocator = mem.Allocator; | ||
| 10 | const Dylib = @import("Dylib.zig"); | ||
| 11 | const Object = @import("Object.zig"); | ||
| 12 | const Zld = @import("Zld.zig"); | ||
| 13 | |||
| 14 | /// Offset into the string table. | ||
| 15 | strx: u32, | ||
| 16 | |||
| 17 | /// Index in GOT table for indirection. | ||
| 18 | got_index: ?u32 = null, | ||
| 19 | |||
| 20 | /// Index in stubs table for late binding. | ||
| 21 | stubs_index: ?u32 = null, | ||
| 22 | |||
| 23 | payload: union(enum) { | ||
| 24 | regular: Regular, | ||
| 25 | tentative: Tentative, | ||
| 26 | proxy: Proxy, | ||
| 27 | undef: Undefined, | ||
| 28 | |||
| 29 | pub fn format(self: @This(), comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { | ||
| 30 | return switch (self) { | ||
| 31 | .regular => |p| p.format(fmt, options, writer), | ||
| 32 | .tentative => |p| p.format(fmt, options, writer), | ||
| 33 | .proxy => |p| p.format(fmt, options, writer), | ||
| 34 | .undef => |p| p.format(fmt, options, writer), | ||
| 35 | }; | ||
| 36 | } | ||
| 37 | }, | ||
| 38 | |||
| 39 | pub const Regular = struct { | ||
| 40 | /// Linkage type. | ||
| 41 | linkage: Linkage, | ||
| 42 | |||
| 43 | /// Symbol address. | ||
| 44 | address: u64 = 0, | ||
| 45 | |||
| 46 | /// Segment ID | ||
| 47 | segment_id: u16 = 0, | ||
| 48 | |||
| 49 | /// Section ID | ||
| 50 | section_id: u16 = 0, | ||
| 51 | |||
| 52 | /// Whether the symbol is a weak ref. | ||
| 53 | weak_ref: bool = false, | ||
| 54 | |||
| 55 | /// Object file where to locate this symbol. | ||
| 56 | /// null means self-reference. | ||
| 57 | file: ?*Object = null, | ||
| 58 | |||
| 59 | local_sym_index: u32 = 0, | ||
| 60 | |||
| 61 | pub const Linkage = enum { | ||
| 62 | translation_unit, | ||
| 63 | linkage_unit, | ||
| 64 | global, | ||
| 65 | }; | ||
| 66 | |||
| 67 | pub fn format(self: Regular, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { | ||
| 68 | _ = fmt; | ||
| 69 | _ = options; | ||
| 70 | try std.fmt.format(writer, "Regular {{ ", .{}); | ||
| 71 | try std.fmt.format(writer, ".linkage = {s}, ", .{self.linkage}); | ||
| 72 | try std.fmt.format(writer, ".address = 0x{x}, ", .{self.address}); | ||
| 73 | try std.fmt.format(writer, ".segment_id = {}, ", .{self.segment_id}); | ||
| 74 | try std.fmt.format(writer, ".section_id = {}, ", .{self.section_id}); | ||
| 75 | if (self.weak_ref) { | ||
| 76 | try std.fmt.format(writer, ".weak_ref, ", .{}); | ||
| 77 | } | ||
| 78 | if (self.file) |file| { | ||
| 79 | try std.fmt.format(writer, ".file = {s}, ", .{file.name.?}); | ||
| 80 | } | ||
| 81 | try std.fmt.format(writer, ".local_sym_index = {}, ", .{self.local_sym_index}); | ||
| 82 | try std.fmt.format(writer, "}}", .{}); | ||
| 83 | } | ||
| 84 | |||
| 85 | pub fn sectionId(self: Regular, zld: *Zld) u8 { | ||
| 86 | // TODO there might be a more generic way of doing this. | ||
| 87 | var section: u8 = 0; | ||
| 88 | for (zld.load_commands.items) |cmd, cmd_id| { | ||
| 89 | if (cmd != .Segment) break; | ||
| 90 | if (cmd_id == self.segment_id) { | ||
| 91 | section += @intCast(u8, self.section_id) + 1; | ||
| 92 | break; | ||
| 93 | } | ||
| 94 | section += @intCast(u8, cmd.Segment.sections.items.len); | ||
| 95 | } | ||
| 96 | return section; | ||
| 97 | } | ||
| 98 | }; | ||
| 99 | |||
| 100 | pub const Tentative = struct { | ||
| 101 | /// Symbol size. | ||
| 102 | size: u64, | ||
| 103 | |||
| 104 | /// Symbol alignment as power of two. | ||
| 105 | alignment: u16, | ||
| 106 | |||
| 107 | /// File where this symbol was referenced. | ||
| 108 | file: ?*Object = null, | ||
| 109 | |||
| 110 | pub fn format(self: Tentative, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { | ||
| 111 | _ = fmt; | ||
| 112 | _ = options; | ||
| 113 | try std.fmt.format(writer, "Tentative {{ ", .{}); | ||
| 114 | try std.fmt.format(writer, ".size = 0x{x}, ", .{self.size}); | ||
| 115 | try std.fmt.format(writer, ".alignment = 0x{x}, ", .{self.alignment}); | ||
| 116 | if (self.file) |file| { | ||
| 117 | try std.fmt.format(writer, ".file = {s}, ", .{file.name.?}); | ||
| 118 | } | ||
| 119 | try std.fmt.format(writer, "}}", .{}); | ||
| 120 | } | ||
| 121 | }; | ||
| 122 | |||
| 123 | pub const Proxy = struct { | ||
| 124 | /// Dylib where to locate this symbol. | ||
| 125 | /// null means self-reference. | ||
| 126 | file: ?*Dylib = null, | ||
| 127 | |||
| 128 | local_sym_index: u32 = 0, | ||
| 129 | |||
| 130 | pub fn dylibOrdinal(proxy: Proxy) u16 { | ||
| 131 | const dylib = proxy.file orelse return 0; | ||
| 132 | return dylib.ordinal.?; | ||
| 133 | } | ||
| 134 | |||
| 135 | pub fn format(self: Proxy, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { | ||
| 136 | _ = fmt; | ||
| 137 | _ = options; | ||
| 138 | try std.fmt.format(writer, "Proxy {{ ", .{}); | ||
| 139 | if (self.file) |file| { | ||
| 140 | try std.fmt.format(writer, ".file = {s}, ", .{file.name.?}); | ||
| 141 | } | ||
| 142 | try std.fmt.format(writer, ".local_sym_index = {d}, ", .{self.local_sym_index}); | ||
| 143 | try std.fmt.format(writer, "}}", .{}); | ||
| 144 | } | ||
| 145 | }; | ||
| 146 | |||
| 147 | pub const Undefined = struct { | ||
| 148 | /// File where this symbol was referenced. | ||
| 149 | /// null means synthetic, e.g., dyld_stub_binder. | ||
| 150 | file: ?*Object = null, | ||
| 151 | |||
| 152 | pub fn format(self: Undefined, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { | ||
| 153 | _ = fmt; | ||
| 154 | _ = options; | ||
| 155 | try std.fmt.format(writer, "Undefined {{ ", .{}); | ||
| 156 | if (self.file) |file| { | ||
| 157 | try std.fmt.format(writer, ".file = {s}, ", .{file.name.?}); | ||
| 158 | } | ||
| 159 | try std.fmt.format(writer, "}}", .{}); | ||
| 160 | } | ||
| 161 | }; | ||
| 162 | |||
| 163 | pub fn format(self: Symbol, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { | ||
| 164 | _ = fmt; | ||
| 165 | _ = options; | ||
| 166 | try std.fmt.format(writer, "Symbol {{", .{}); | ||
| 167 | try std.fmt.format(writer, ".strx = {d}, ", .{self.strx}); | ||
| 168 | if (self.got_index) |got_index| { | ||
| 169 | try std.fmt.format(writer, ".got_index = {}, ", .{got_index}); | ||
| 170 | } | ||
| 171 | if (self.stubs_index) |stubs_index| { | ||
| 172 | try std.fmt.format(writer, ".stubs_index = {}, ", .{stubs_index}); | ||
| 173 | } | ||
| 174 | try std.fmt.format(writer, "{}, ", .{self.payload}); | ||
| 175 | try std.fmt.format(writer, "}}", .{}); | ||
| 176 | } | ||
| 177 | |||
| 178 | pub fn isTemp(symbol: Symbol, zld: *Zld) bool { | ||
| 179 | const sym_name = zld.getString(symbol.strx); | ||
| 180 | switch (symbol.payload) { | ||
| 181 | .regular => |regular| { | ||
| 182 | if (regular.linkage == .translation_unit) { | ||
| 183 | return mem.startsWith(u8, sym_name, "l") or mem.startsWith(u8, sym_name, "L"); | ||
| 184 | } | ||
| 185 | }, | ||
| 186 | else => {}, | ||
| 187 | } | ||
| 188 | return false; | ||
| 189 | } | ||
| 190 | |||
| 191 | pub fn asNlist(symbol: *Symbol, zld: *Zld) !macho.nlist_64 { | ||
| 192 | const nlist = nlist: { | ||
| 193 | switch (symbol.payload) { | ||
| 194 | .regular => |regular| { | ||
| 195 | var nlist = macho.nlist_64{ | ||
| 196 | .n_strx = symbol.strx, | ||
| 197 | .n_type = macho.N_SECT, | ||
| 198 | .n_sect = regular.sectionId(zld), | ||
| 199 | .n_desc = 0, | ||
| 200 | .n_value = regular.address, | ||
| 201 | }; | ||
| 202 | |||
| 203 | if (regular.linkage != .translation_unit) { | ||
| 204 | nlist.n_type |= macho.N_EXT; | ||
| 205 | } | ||
| 206 | if (regular.linkage == .linkage_unit) { | ||
| 207 | nlist.n_type |= macho.N_PEXT; | ||
| 208 | nlist.n_desc |= macho.N_WEAK_DEF; | ||
| 209 | } | ||
| 210 | |||
| 211 | break :nlist nlist; | ||
| 212 | }, | ||
| 213 | .tentative => { | ||
| 214 | // TODO | ||
| 215 | break :nlist macho.nlist_64{ | ||
| 216 | .n_strx = symbol.strx, | ||
| 217 | .n_type = macho.N_UNDF, | ||
| 218 | .n_sect = 0, | ||
| 219 | .n_desc = 0, | ||
| 220 | .n_value = 0, | ||
| 221 | }; | ||
| 222 | }, | ||
| 223 | .proxy => |proxy| { | ||
| 224 | break :nlist macho.nlist_64{ | ||
| 225 | .n_strx = symbol.strx, | ||
| 226 | .n_type = macho.N_UNDF | macho.N_EXT, | ||
| 227 | .n_sect = 0, | ||
| 228 | .n_desc = (proxy.dylibOrdinal() * macho.N_SYMBOL_RESOLVER) | macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY, | ||
| 229 | .n_value = 0, | ||
| 230 | }; | ||
| 231 | }, | ||
| 232 | .undef => { | ||
| 233 | // TODO | ||
| 234 | break :nlist macho.nlist_64{ | ||
| 235 | .n_strx = symbol.strx, | ||
| 236 | .n_type = macho.N_UNDF, | ||
| 237 | .n_sect = 0, | ||
| 238 | .n_desc = 0, | ||
| 239 | .n_value = 0, | ||
| 240 | }; | ||
| 241 | }, | ||
| 242 | } | ||
| 243 | }; | ||
| 244 | return nlist; | ||
| 245 | } | ||
| 246 | |||
| 247 | pub fn isStab(sym: macho.nlist_64) bool { | ||
| 248 | return (macho.N_STAB & sym.n_type) != 0; | ||
| 249 | } | ||
| 250 | |||
| 251 | pub fn isPext(sym: macho.nlist_64) bool { | ||
| 252 | return (macho.N_PEXT & sym.n_type) != 0; | ||
| 253 | } | ||
| 254 | |||
| 255 | pub fn isExt(sym: macho.nlist_64) bool { | ||
| 256 | return (macho.N_EXT & sym.n_type) != 0; | ||
| 257 | } | ||
| 258 | |||
| 259 | pub fn isSect(sym: macho.nlist_64) bool { | ||
| 260 | const type_ = macho.N_TYPE & sym.n_type; | ||
| 261 | return type_ == macho.N_SECT; | ||
| 262 | } | ||
| 263 | |||
| 264 | pub fn isUndf(sym: macho.nlist_64) bool { | ||
| 265 | const type_ = macho.N_TYPE & sym.n_type; | ||
| 266 | return type_ == macho.N_UNDF; | ||
| 267 | } | ||
| 268 | |||
| 269 | pub fn isIndr(sym: macho.nlist_64) bool { | ||
| 270 | const type_ = macho.N_TYPE & sym.n_type; | ||
| 271 | return type_ == macho.N_INDR; | ||
| 272 | } | ||
| 273 | |||
| 274 | pub fn isAbs(sym: macho.nlist_64) bool { | ||
| 275 | const type_ = macho.N_TYPE & sym.n_type; | ||
| 276 | return type_ == macho.N_ABS; | ||
| 277 | } | ||
| 278 | |||
| 279 | pub fn isWeakDef(sym: macho.nlist_64) bool { | ||
| 280 | return (sym.n_desc & macho.N_WEAK_DEF) != 0; | ||
| 281 | } | ||
| 282 | |||
| 283 | pub fn isWeakRef(sym: macho.nlist_64) bool { | ||
| 284 | return (sym.n_desc & macho.N_WEAK_REF) != 0; | ||
| 285 | } | ||
src/link/MachO/TextBlock.zig+35-29| ... | @@ -5,10 +5,9 @@ const commands = @import("commands.zig"); | ... | @@ -5,10 +5,9 @@ const commands = @import("commands.zig"); |
| 5 | const log = std.log.scoped(.text_block); | 5 | const log = std.log.scoped(.text_block); |
| 6 | const macho = std.macho; | 6 | const macho = std.macho; |
| 7 | const mem = std.mem; | 7 | const mem = std.mem; |
| 8 | const reloc = @import("reloc.zig"); | ||
| 9 | 8 | ||
| 10 | const Allocator = mem.Allocator; | 9 | const Allocator = mem.Allocator; |
| 11 | const Relocation = reloc.Relocation; | 10 | const Arch = std.Target.Cpu.Arch; |
| 12 | const Zld = @import("Zld.zig"); | 11 | const Zld = @import("Zld.zig"); |
| 13 | 12 | ||
| 14 | allocator: *Allocator, | 13 | allocator: *Allocator, |
| ... | @@ -102,6 +101,15 @@ pub const Stab = union(enum) { | ... | @@ -102,6 +101,15 @@ pub const Stab = union(enum) { |
| 102 | } | 101 | } |
| 103 | }; | 102 | }; |
| 104 | 103 | ||
| 104 | pub const Relocation = struct { | ||
| 105 | inner: macho.relocation_info, | ||
| 106 | where: enum { | ||
| 107 | local, | ||
| 108 | import, | ||
| 109 | }, | ||
| 110 | where_index: u32, | ||
| 111 | }; | ||
| 112 | |||
| 105 | pub fn init(allocator: *Allocator) TextBlock { | 113 | pub fn init(allocator: *Allocator) TextBlock { |
| 106 | return .{ | 114 | return .{ |
| 107 | .allocator = allocator, | 115 | .allocator = allocator, |
| ... | @@ -137,18 +145,10 @@ pub fn resolveRelocs(self: *TextBlock, zld: *Zld) !void { | ... | @@ -137,18 +145,10 @@ pub fn resolveRelocs(self: *TextBlock, zld: *Zld) !void { |
| 137 | 145 | ||
| 138 | const source_addr = blk: { | 146 | const source_addr = blk: { |
| 139 | const sym = zld.locals.items[self.local_sym_index]; | 147 | const sym = zld.locals.items[self.local_sym_index]; |
| 140 | break :blk sym.payload.regular.address + rel.offset; | 148 | break :blk sym.n_value + rel.offset; |
| 141 | }; | 149 | }; |
| 142 | const target_addr = blk: { | 150 | const target_addr = blk: { |
| 143 | const is_via_got = switch (rel.payload) { | 151 | if (isGotIndirection(rel, zld.target.?.cpu.arch)) { |
| 144 | .pointer_to_got => true, | ||
| 145 | .page => |page| page.kind == .got, | ||
| 146 | .page_off => |page_off| page_off.kind == .got, | ||
| 147 | .load => |load| load.kind == .got, | ||
| 148 | else => false, | ||
| 149 | }; | ||
| 150 | |||
| 151 | if (is_via_got) { | ||
| 152 | const dc_seg = zld.load_commands.items[zld.data_const_segment_cmd_index.?].Segment; | 152 | const dc_seg = zld.load_commands.items[zld.data_const_segment_cmd_index.?].Segment; |
| 153 | const got = dc_seg.sections.items[zld.got_section_index.?]; | 153 | const got = dc_seg.sections.items[zld.got_section_index.?]; |
| 154 | const got_index = rel.target.got_index orelse { | 154 | const got_index = rel.target.got_index orelse { |
| ... | @@ -228,31 +228,18 @@ pub fn print_this(self: *const TextBlock, zld: *Zld) void { | ... | @@ -228,31 +228,18 @@ pub fn print_this(self: *const TextBlock, zld: *Zld) void { |
| 228 | log.warn(" stab: {}", .{stab}); | 228 | log.warn(" stab: {}", .{stab}); |
| 229 | } | 229 | } |
| 230 | if (self.aliases.items.len > 0) { | 230 | if (self.aliases.items.len > 0) { |
| 231 | log.warn(" aliases:", .{}); | 231 | log.warn(" aliases: {any}", .{self.aliases.items}); |
| 232 | for (self.aliases.items) |index| { | ||
| 233 | log.warn(" {}: {}", .{ index, zld.locals.items[index] }); | ||
| 234 | } | ||
| 235 | } | 232 | } |
| 236 | if (self.references.count() > 0) { | 233 | if (self.references.count() > 0) { |
| 237 | log.warn(" references:", .{}); | 234 | log.warn(" references: {any}", .{self.references.keys()}); |
| 238 | for (self.references.keys()) |index| { | ||
| 239 | log.warn(" {}: {}", .{ index, zld.locals.items[index] }); | ||
| 240 | } | ||
| 241 | } | 235 | } |
| 242 | if (self.contained) |contained| { | 236 | if (self.contained) |contained| { |
| 243 | log.warn(" contained symbols:", .{}); | 237 | log.warn(" contained symbols:", .{}); |
| 244 | for (contained) |sym_at_off| { | 238 | for (contained) |sym_at_off| { |
| 245 | if (sym_at_off.stab) |stab| { | 239 | if (sym_at_off.stab) |stab| { |
| 246 | log.warn(" {}: {}, stab: {}\n", .{ | 240 | log.warn(" {}: {}, stab: {}", .{ sym_at_off.offset, sym_at_off.local_sym_index, stab }); |
| 247 | sym_at_off.offset, | ||
| 248 | zld.locals.items[sym_at_off.local_sym_index], | ||
| 249 | stab, | ||
| 250 | }); | ||
| 251 | } else { | 241 | } else { |
| 252 | log.warn(" {}: {}\n", .{ | 242 | log.warn(" {}: {}", .{ sym_at_off.offset, sym_at_off.local_sym_index }); |
| 253 | sym_at_off.offset, | ||
| 254 | zld.locals.items[sym_at_off.local_sym_index], | ||
| 255 | }); | ||
| 256 | } | 243 | } |
| 257 | } | 244 | } |
| 258 | } | 245 | } |
| ... | @@ -282,3 +269,22 @@ pub fn print(self: *const TextBlock, zld: *Zld) void { | ... | @@ -282,3 +269,22 @@ pub fn print(self: *const TextBlock, zld: *Zld) void { |
| 282 | } | 269 | } |
| 283 | self.print_this(zld); | 270 | self.print_this(zld); |
| 284 | } | 271 | } |
| 272 | |||
| 273 | fn isGotIndirection(rel: macho.relocation_info, arch: Arch) bool { | ||
| 274 | return switch (arch) { | ||
| 275 | .aarch64 => switch (@intToEnum(macho.reloc_type_arm64, rel.r_type)) { | ||
| 276 | .ARM64_RELOC_POINTER_TO_GOT, | ||
| 277 | .ARM64_RELOC_GOT_LOAD_PAGE21, | ||
| 278 | .ARM64_RELOC_GOT_LOAD_PAGEOFF12, | ||
| 279 | => true, | ||
| 280 | else => false, | ||
| 281 | }, | ||
| 282 | .x86_64 => switch (@intToEnum(macho.reloc_type_x86_64, rel.r_type)) { | ||
| 283 | .X86_64_RELOC_GOT, | ||
| 284 | .X86_64_RELOC_GOT_LOAD, | ||
| 285 | => true, | ||
| 286 | else => false, | ||
| 287 | }, | ||
| 288 | else => unreachable, | ||
| 289 | }; | ||
| 290 | } |
src/link/MachO/Zld.zig+26-48| ... | @@ -105,7 +105,6 @@ imports: std.ArrayListUnmanaged(macho.nlist_64) = .{}, | ... | @@ -105,7 +105,6 @@ imports: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| 105 | undefs: std.ArrayListUnmanaged(macho.nlist_64) = .{}, | 105 | undefs: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| 106 | tentatives: std.ArrayListUnmanaged(macho.nlist_64) = .{}, | 106 | tentatives: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| 107 | symbol_resolver: std.StringArrayHashMapUnmanaged(SymbolWithLoc) = .{}, | 107 | symbol_resolver: std.StringArrayHashMapUnmanaged(SymbolWithLoc) = .{}, |
| 108 | object_mapping: std.AutoHashMapUnmanaged(u16, []u32) = .{}, | ||
| 109 | 108 | ||
| 110 | strtab: std.ArrayListUnmanaged(u8) = .{}, | 109 | strtab: std.ArrayListUnmanaged(u8) = .{}, |
| 111 | 110 | ||
| ... | @@ -199,14 +198,6 @@ pub fn deinit(self: *Zld) void { | ... | @@ -199,14 +198,6 @@ pub fn deinit(self: *Zld) void { |
| 199 | } | 198 | } |
| 200 | self.symbol_resolver.deinit(self.allocator); | 199 | self.symbol_resolver.deinit(self.allocator); |
| 201 | 200 | ||
| 202 | { | ||
| 203 | var it = self.object_mapping.valueIterator(); | ||
| 204 | while (it.next()) |value_ptr| { | ||
| 205 | self.allocator.free(value_ptr.*); | ||
| 206 | } | ||
| 207 | } | ||
| 208 | self.object_mapping.deinit(self.allocator); | ||
| 209 | |||
| 210 | self.strtab.deinit(self.allocator); | 201 | self.strtab.deinit(self.allocator); |
| 211 | 202 | ||
| 212 | // TODO dealloc all blocks | 203 | // TODO dealloc all blocks |
| ... | @@ -251,33 +242,33 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg | ... | @@ -251,33 +242,33 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg |
| 251 | try self.resolveSymbols(); | 242 | try self.resolveSymbols(); |
| 252 | 243 | ||
| 253 | log.warn("locals", .{}); | 244 | log.warn("locals", .{}); |
| 254 | for (self.locals.items) |sym| { | 245 | for (self.locals.items) |sym, id| { |
| 255 | log.warn(" | {s}: {}", .{ self.getString(sym.n_strx), sym }); | 246 | log.warn(" {d}: {s}, {}", .{ id, self.getString(sym.n_strx), sym }); |
| 256 | } | 247 | } |
| 257 | 248 | ||
| 258 | log.warn("globals", .{}); | 249 | log.warn("globals", .{}); |
| 259 | for (self.globals.items) |sym| { | 250 | for (self.globals.items) |sym, id| { |
| 260 | log.warn(" | {s}: {}", .{ self.getString(sym.n_strx), sym }); | 251 | log.warn(" {d}: {s}, {}", .{ id, self.getString(sym.n_strx), sym }); |
| 261 | } | 252 | } |
| 262 | 253 | ||
| 263 | log.warn("tentatives", .{}); | 254 | log.warn("tentatives", .{}); |
| 264 | for (self.tentatives.items) |sym| { | 255 | for (self.tentatives.items) |sym, id| { |
| 265 | log.warn(" | {s}: {}", .{ self.getString(sym.n_strx), sym }); | 256 | log.warn(" {d}: {s}, {}", .{ id, self.getString(sym.n_strx), sym }); |
| 266 | } | 257 | } |
| 267 | 258 | ||
| 268 | log.warn("undefines", .{}); | 259 | log.warn("undefines", .{}); |
| 269 | for (self.undefs.items) |sym| { | 260 | for (self.undefs.items) |sym, id| { |
| 270 | log.warn(" | {s}: {}", .{ self.getString(sym.n_strx), sym }); | 261 | log.warn(" {d}: {s}, {}", .{ id, self.getString(sym.n_strx), sym }); |
| 271 | } | 262 | } |
| 272 | 263 | ||
| 273 | log.warn("imports", .{}); | 264 | log.warn("imports", .{}); |
| 274 | for (self.imports.items) |sym| { | 265 | for (self.imports.items) |sym, id| { |
| 275 | log.warn(" | {s}: {}", .{ self.getString(sym.n_strx), sym }); | 266 | log.warn(" {d}: {s}, {}", .{ id, self.getString(sym.n_strx), sym }); |
| 276 | } | 267 | } |
| 277 | 268 | ||
| 278 | log.warn("symbol resolver", .{}); | 269 | log.warn("symbol resolver", .{}); |
| 279 | for (self.symbol_resolver.keys()) |key| { | 270 | for (self.symbol_resolver.keys()) |key| { |
| 280 | log.warn(" | {s} => {}", .{ key, self.symbol_resolver.get(key).? }); | 271 | log.warn(" {s} => {}", .{ key, self.symbol_resolver.get(key).? }); |
| 281 | } | 272 | } |
| 282 | 273 | ||
| 283 | log.warn("mappings", .{}); | 274 | log.warn("mappings", .{}); |
| ... | @@ -285,7 +276,7 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg | ... | @@ -285,7 +276,7 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg |
| 285 | const object_id = @intCast(u16, id); | 276 | const object_id = @intCast(u16, id); |
| 286 | log.warn(" in object {s}", .{object.name.?}); | 277 | log.warn(" in object {s}", .{object.name.?}); |
| 287 | for (object.symtab.items) |sym, sym_id| { | 278 | for (object.symtab.items) |sym, sym_id| { |
| 288 | if (self.localSymIndex(object_id, @intCast(u32, sym_id))) |local_id| { | 279 | if (object.symbol_mapping.get(@intCast(u32, sym_id))) |local_id| { |
| 289 | log.warn(" | {d} => {d}", .{ sym_id, local_id }); | 280 | log.warn(" | {d} => {d}", .{ sym_id, local_id }); |
| 290 | } else { | 281 | } else { |
| 291 | log.warn(" | {d} no local mapping for {s}", .{ sym_id, object.getString(sym.n_strx) }); | 282 | log.warn(" | {d} no local mapping for {s}", .{ sym_id, object.getString(sym.n_strx) }); |
| ... | @@ -293,8 +284,19 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg | ... | @@ -293,8 +284,19 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg |
| 293 | } | 284 | } |
| 294 | } | 285 | } |
| 295 | 286 | ||
| 287 | try self.parseTextBlocks(); | ||
| 288 | |||
| 289 | var it = self.blocks.iterator(); | ||
| 290 | while (it.next()) |entry| { | ||
| 291 | const seg = self.load_commands.items[entry.key_ptr.seg].Segment; | ||
| 292 | const sect = seg.sections.items[entry.key_ptr.sect]; | ||
| 293 | |||
| 294 | log.warn("\n\n{s},{s} contents:", .{ segmentName(sect), sectionName(sect) }); | ||
| 295 | log.warn(" {}", .{sect}); | ||
| 296 | entry.value_ptr.*.print(self); | ||
| 297 | } | ||
| 298 | |||
| 296 | return error.TODO; | 299 | return error.TODO; |
| 297 | // try self.parseTextBlocks(); | ||
| 298 | // try self.sortSections(); | 300 | // try self.sortSections(); |
| 299 | // try self.addRpaths(args.rpaths); | 301 | // try self.addRpaths(args.rpaths); |
| 300 | // try self.addDataInCodeLC(); | 302 | // try self.addDataInCodeLC(); |
| ... | @@ -305,16 +307,6 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg | ... | @@ -305,16 +307,6 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg |
| 305 | // self.allocateLinkeditSegment(); | 307 | // self.allocateLinkeditSegment(); |
| 306 | // try self.allocateTextBlocks(); | 308 | // try self.allocateTextBlocks(); |
| 307 | 309 | ||
| 308 | // // var it = self.blocks.iterator(); | ||
| 309 | // // while (it.next()) |entry| { | ||
| 310 | // // const seg = self.load_commands.items[entry.key_ptr.seg].Segment; | ||
| 311 | // // const sect = seg.sections.items[entry.key_ptr.sect]; | ||
| 312 | |||
| 313 | // // log.warn("\n\n{s},{s} contents:", .{ segmentName(sect), sectionName(sect) }); | ||
| 314 | // // log.warn(" {}", .{sect}); | ||
| 315 | // // entry.value_ptr.*.print(self); | ||
| 316 | // // } | ||
| 317 | |||
| 318 | // try self.flush(); | 310 | // try self.flush(); |
| 319 | } | 311 | } |
| 320 | 312 | ||
| ... | @@ -1414,10 +1406,6 @@ fn resolveSymbolsInObject(self: *Zld, object_id: u16) !void { | ... | @@ -1414,10 +1406,6 @@ fn resolveSymbolsInObject(self: *Zld, object_id: u16) !void { |
| 1414 | 1406 | ||
| 1415 | log.warn("resolving symbols in '{s}'", .{object.name}); | 1407 | log.warn("resolving symbols in '{s}'", .{object.name}); |
| 1416 | 1408 | ||
| 1417 | const mapping = try self.allocator.alloc(u32, object.symtab.items.len); | ||
| 1418 | mem.set(u32, mapping, 0); | ||
| 1419 | try self.object_mapping.putNoClobber(self.allocator, object_id, mapping); | ||
| 1420 | |||
| 1421 | for (object.symtab.items) |sym, id| { | 1409 | for (object.symtab.items) |sym, id| { |
| 1422 | const sym_id = @intCast(u32, id); | 1410 | const sym_id = @intCast(u32, id); |
| 1423 | const sym_name = object.getString(sym.n_strx); | 1411 | const sym_name = object.getString(sym.n_strx); |
| ... | @@ -1464,7 +1452,7 @@ fn resolveSymbolsInObject(self: *Zld, object_id: u16) !void { | ... | @@ -1464,7 +1452,7 @@ fn resolveSymbolsInObject(self: *Zld, object_id: u16) !void { |
| 1464 | .n_desc = 0, | 1452 | .n_desc = 0, |
| 1465 | .n_value = sym.n_value, | 1453 | .n_value = sym.n_value, |
| 1466 | }); | 1454 | }); |
| 1467 | mapping[sym_id] = local_sym_index; | 1455 | try object.symbol_mapping.putNoClobber(self.allocator, sym_id, local_sym_index); |
| 1468 | 1456 | ||
| 1469 | // If the symbol's scope is not local aka translation unit, then we need work out | 1457 | // If the symbol's scope is not local aka translation unit, then we need work out |
| 1470 | // if we should save the symbol as a global, or potentially flag the error. | 1458 | // if we should save the symbol as a global, or potentially flag the error. |
| ... | @@ -2987,15 +2975,6 @@ pub fn getString(self: *Zld, off: u32) []const u8 { | ... | @@ -2987,15 +2975,6 @@ pub fn getString(self: *Zld, off: u32) []const u8 { |
| 2987 | return mem.spanZ(@ptrCast([*:0]const u8, self.strtab.items.ptr + off)); | 2975 | return mem.spanZ(@ptrCast([*:0]const u8, self.strtab.items.ptr + off)); |
| 2988 | } | 2976 | } |
| 2989 | 2977 | ||
| 2990 | fn localSymIndex(self: Zld, object_id: u16, orig_id: u32) ?u32 { | ||
| 2991 | const mapping = self.object_mapping.get(object_id) orelse return null; | ||
| 2992 | const local_sym_index = mapping[orig_id]; | ||
| 2993 | if (local_sym_index == 0) { | ||
| 2994 | return null; | ||
| 2995 | } | ||
| 2996 | return local_sym_index; | ||
| 2997 | } | ||
| 2998 | |||
| 2999 | pub fn symbolIsStab(sym: macho.nlist_64) bool { | 2978 | pub fn symbolIsStab(sym: macho.nlist_64) bool { |
| 3000 | return (macho.N_STAB & sym.n_type) != 0; | 2979 | return (macho.N_STAB & sym.n_type) != 0; |
| 3001 | } | 2980 | } |
| ... | @@ -3045,10 +3024,9 @@ pub fn symbolIsNull(sym: macho.nlist_64) bool { | ... | @@ -3045,10 +3024,9 @@ pub fn symbolIsNull(sym: macho.nlist_64) bool { |
| 3045 | return sym.n_value == 0 and sym.n_desc == 0 and sym.n_type == 0 and sym.n_strx == 0 and sym.n_sect == 0; | 3024 | return sym.n_value == 0 and sym.n_desc == 0 and sym.n_type == 0 and sym.n_strx == 0 and sym.n_sect == 0; |
| 3046 | } | 3025 | } |
| 3047 | 3026 | ||
| 3048 | pub fn symbolIsTemp(self: Zld, sym: macho.nlist_64) bool { | 3027 | pub fn symbolIsTemp(sym: macho.nlist_64, sym_name: []const u8) bool { |
| 3049 | if (!symbolIsSect(sym)) return false; | 3028 | if (!symbolIsSect(sym)) return false; |
| 3050 | if (symbolIsExt(sym)) return false; | 3029 | if (symbolIsExt(sym)) return false; |
| 3051 | const sym_name = self.getString(sym.n_strx); | ||
| 3052 | return mem.startsWith(u8, sym_name, "l") or mem.startsWith(u8, sym_name, "L"); | 3030 | return mem.startsWith(u8, sym_name, "l") or mem.startsWith(u8, sym_name, "L"); |
| 3053 | } | 3031 | } |
| 3054 | 3032 |