Commit 7b4063d558
Changed files (3)
src
link
src/link/MachO/Object.zig
@@ -28,7 +28,6 @@ name: ?[]const u8 = null,
mtime: ?u64 = null,
load_commands: std.ArrayListUnmanaged(LoadCommand) = .{},
-sections: std.ArrayListUnmanaged(Section) = .{},
segment_cmd_index: ?u16 = null,
symtab_cmd_index: ?u16 = null,
@@ -49,32 +48,10 @@ dwarf_debug_ranges_index: ?u16 = null,
symtab: std.ArrayListUnmanaged(macho.nlist_64) = .{},
strtab: std.ArrayListUnmanaged(u8) = .{},
-symbols: std.ArrayListUnmanaged(*Symbol) = .{},
-stabs: std.ArrayListUnmanaged(*Symbol) = .{},
initializers: std.ArrayListUnmanaged(u32) = .{},
data_in_code_entries: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{},
-pub const Section = struct {
- inner: macho.section_64,
- code: []u8,
- relocs: ?[]*Relocation,
- target_map: ?struct {
- segment_id: u16,
- section_id: u16,
- offset: u32,
- } = null,
-
- pub fn deinit(self: *Section, allocator: *Allocator) void {
- allocator.free(self.code);
-
- if (self.relocs) |relocs| {
- for (relocs) |rel| {
- allocator.destroy(rel);
- }
- allocator.free(relocs);
- }
- }
-};
+symbols: std.ArrayListUnmanaged(*Symbol) = .{},
const DebugInfo = struct {
inner: dwarf.DwarfInfo,
@@ -177,19 +154,11 @@ pub fn deinit(self: *Object) void {
lc.deinit(self.allocator);
}
self.load_commands.deinit(self.allocator);
-
- for (self.sections.items) |*sect| {
- sect.deinit(self.allocator);
- }
- self.sections.deinit(self.allocator);
-
- self.symbols.deinit(self.allocator);
- self.stabs.deinit(self.allocator);
-
self.data_in_code_entries.deinit(self.allocator);
self.initializers.deinit(self.allocator);
self.symtab.deinit(self.allocator);
self.strtab.deinit(self.allocator);
+ self.symbols.deinit(self.allocator);
if (self.name) |n| {
self.allocator.free(n);
@@ -231,10 +200,8 @@ pub fn parse(self: *Object) !void {
self.header = header;
try self.readLoadCommands(reader);
- try self.parseSections();
try self.parseSymtab();
try self.parseDataInCode();
- try self.parseInitializers();
}
pub fn readLoadCommands(self: *Object, reader: anytype) !void {
@@ -305,250 +272,253 @@ pub fn readLoadCommands(self: *Object, reader: anytype) !void {
}
}
-pub fn parseSections(self: *Object) !void {
- const seg = self.load_commands.items[self.segment_cmd_index.?].Segment;
-
- log.debug("parsing sections in {s}", .{self.name.?});
-
- try self.sections.ensureCapacity(self.allocator, seg.sections.items.len);
+const NlistWithIndex = struct {
+ nlist: macho.nlist_64,
+ index: u32,
- for (seg.sections.items) |sect| {
- log.debug("parsing section '{s},{s}'", .{ segmentName(sect), sectionName(sect) });
- // Read sections' code
- var code = try self.allocator.alloc(u8, @intCast(usize, sect.size));
- _ = try self.file.?.preadAll(code, sect.offset);
-
- var section = Section{
- .inner = sect,
- .code = code,
- .relocs = null,
- };
+ pub fn cmp(_: void, lhs: @This(), rhs: @This()) bool {
+ return lhs.nlist.n_value < rhs.nlist.n_value;
+ }
- // Parse relocations
- if (sect.nreloc > 0) {
- var raw_relocs = try self.allocator.alloc(u8, @sizeOf(macho.relocation_info) * sect.nreloc);
- defer self.allocator.free(raw_relocs);
+ fn filterNlistsInSection(symbols: []@This(), sect_id: u8) []@This() {
+ var start: usize = 0;
+ var end: usize = symbols.len;
- _ = try self.file.?.preadAll(raw_relocs, sect.reloff);
+ while (true) {
+ var change = false;
+ if (symbols[start].nlist.n_sect != sect_id) {
+ start += 1;
+ change = true;
+ }
+ if (symbols[end - 1].nlist.n_sect != sect_id) {
+ end -= 1;
+ change = true;
+ }
- section.relocs = try reloc.parse(
- self.allocator,
- self.arch.?,
- section.code,
- mem.bytesAsSlice(macho.relocation_info, raw_relocs),
- );
+ if (start == end) break;
+ if (!change) break;
}
- self.sections.appendAssumeCapacity(section);
+ return symbols[start..end];
}
-}
-
-pub fn parseTextBlocks(self: *Object, zld: *Zld) !*TextBlock {
- const seg = self.load_commands.items[self.segment_cmd_index.?].Segment;
+};
- log.warn("analysing {s}", .{self.name.?});
+fn filterRelocs(relocs: []macho.relocation_info, start: u64, end: u64) []macho.relocation_info {
+ if (relocs.len == 0) return relocs;
- const dysymtab = self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab;
+ var start_id: usize = 0;
+ var end_id: usize = relocs.len;
- const SymWithIndex = struct {
- nlist: macho.nlist_64,
- index: u32,
-
- pub fn cmp(_: void, lhs: @This(), rhs: @This()) bool {
- return lhs.nlist.n_value < rhs.nlist.n_value;
+ while (true) {
+ var change = false;
+ if (relocs[start_id].r_address > end) {
+ start_id += 1;
+ change = true;
}
-
- fn filterSymsInSection(symbols: []@This(), sect_id: u8) []@This() {
- var start: usize = 0;
- var end: usize = symbols.len;
-
- while (true) {
- var change = false;
- if (symbols[start].nlist.n_sect != sect_id) {
- start += 1;
- change = true;
- }
- if (symbols[end - 1].nlist.n_sect != sect_id) {
- end -= 1;
- change = true;
- }
-
- if (start == end) break;
- if (!change) break;
- }
-
- return symbols[start..end];
+ if (relocs[end_id - 1].r_address < start) {
+ end_id -= 1;
+ change = true;
}
- fn filterRelocs(relocs: []macho.relocation_info, start: u64, end: u64) []macho.relocation_info {
- if (relocs.len == 0) return relocs;
+ if (start_id == end_id) break;
+ if (!change) break;
+ }
- var start_id: usize = 0;
- var end_id: usize = relocs.len;
+ return relocs[start_id..end_id];
+}
- while (true) {
- var change = false;
- if (relocs[start_id].r_address > end) {
- start_id += 1;
- change = true;
- }
- if (relocs[end_id - 1].r_address < start) {
- end_id -= 1;
- change = true;
- }
+const SeniorityContext = struct {
+ zld: *Zld,
+};
+fn cmpSymBySeniority(context: SeniorityContext, lhs: u32, rhs: u32) bool {
+ const lreg = context.zld.locals.items[lhs].payload.regular;
+ const rreg = context.zld.locals.items[rhs].payload.regular;
+
+ return switch (rreg.linkage) {
+ .global => true,
+ .linkage_unit => lreg.linkage == .translation_unit,
+ else => false,
+ };
+}
- if (start_id == end_id) break;
- if (!change) break;
- }
+pub fn parseTextBlocks(self: *Object, zld: *Zld) !?*TextBlock {
+ const seg = self.load_commands.items[self.segment_cmd_index.?].Segment;
- return relocs[start_id..end_id];
- }
- };
+ log.warn("analysing {s}", .{self.name.?});
+ const dysymtab = self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab;
+ // We only care about defined symbols, so filter every other out.
const nlists = self.symtab.items[dysymtab.ilocalsym..dysymtab.iundefsym];
- var sorted_syms = std.ArrayList(SymWithIndex).init(self.allocator);
- defer sorted_syms.deinit();
- try sorted_syms.ensureTotalCapacity(nlists.len);
+ var sorted_nlists = std.ArrayList(NlistWithIndex).init(self.allocator);
+ defer sorted_nlists.deinit();
+ try sorted_nlists.ensureTotalCapacity(nlists.len);
for (nlists) |nlist, index| {
- sorted_syms.appendAssumeCapacity(.{
+ sorted_nlists.appendAssumeCapacity(.{
.nlist = nlist,
.index = @intCast(u32, index + dysymtab.ilocalsym),
});
}
- std.sort.sort(SymWithIndex, sorted_syms.items, {}, SymWithIndex.cmp);
+ std.sort.sort(NlistWithIndex, sorted_nlists.items, {}, NlistWithIndex.cmp);
+
+ var last_block: ?*TextBlock = null;
for (seg.sections.items) |sect, sect_id| {
- log.warn("section {s},{s}", .{ segmentName(sect), sectionName(sect) });
+ log.warn("putting section '{s},{s}' as a TextBlock", .{
+ segmentName(sect),
+ sectionName(sect),
+ });
+ // Get matching segment/section in the final artifact.
const match = (try zld.getMatchingSection(sect)) orelse {
log.warn("unhandled section", .{});
continue;
};
- // Read code
+ // Read section's code
var code = try self.allocator.alloc(u8, @intCast(usize, sect.size));
defer self.allocator.free(code);
_ = try self.file.?.preadAll(code, sect.offset);
- // Read and parse relocs
- const raw_relocs = try self.allocator.alloc(u8, @sizeOf(macho.relocation_info) * sect.nreloc);
- defer self.allocator.free(raw_relocs);
- _ = try self.file.?.preadAll(raw_relocs, sect.reloff);
- const relocs = mem.bytesAsSlice(macho.relocation_info, raw_relocs);
+ // Is there any padding between symbols within the section?
+ const is_padded = self.header.?.flags & macho.MH_SUBSECTIONS_VIA_SYMBOLS != 0;
+ // Section alignment will be the assumed alignment per symbol.
const alignment = sect.@"align";
- if (self.header.?.flags & macho.MH_SUBSECTIONS_VIA_SYMBOLS != 0) {
- const syms = SymWithIndex.filterSymsInSection(sorted_syms.items, @intCast(u8, sect_id + 1));
-
- if (syms.len == 0) {
- // One large text block referenced by section offsets only
- log.warn("TextBlock", .{});
- log.warn(" | referenced by section offsets", .{});
- log.warn(" | start_addr = {}", .{sect.addr});
- log.warn(" | end_addr = {}", .{sect.size});
- log.warn(" | size = {}", .{sect.size});
- log.warn(" | alignment = 0x{x}", .{alignment});
- log.warn(" | segment_id = {}", .{match.seg});
- log.warn(" | section_id = {}", .{match.sect});
- log.warn(" | relocs: {any}", .{relocs});
- }
+ next: {
+ if (is_padded) blocks: {
+ const filtered_nlists = NlistWithIndex.filterNlistsInSection(
+ sorted_nlists.items,
+ @intCast(u8, sect_id + 1),
+ );
+
+ if (filtered_nlists.len == 0) break :blocks;
- var indices = std.ArrayList(u32).init(self.allocator);
- defer indices.deinit();
+ var nlist_indices = std.ArrayList(u32).init(self.allocator);
+ defer nlist_indices.deinit();
- var i: u32 = 0;
- while (i < syms.len) : (i += 1) {
- const curr = syms[i];
- try indices.append(i);
+ var i: u32 = 0;
+ while (i < filtered_nlists.len) : (i += 1) {
+ const curr = filtered_nlists[i];
+ try nlist_indices.append(curr.index);
- const next: ?SymWithIndex = if (i + 1 < syms.len)
- syms[i + 1]
- else
- null;
+ const next: ?NlistWithIndex = if (i + 1 < filtered_nlists.len)
+ filtered_nlists[i + 1]
+ else
+ null;
- if (next) |n| {
- if (curr.nlist.n_value == n.nlist.n_value) {
- continue;
+ if (next) |n| {
+ if (curr.nlist.n_value == n.nlist.n_value) {
+ continue;
+ }
}
- }
- const start_addr = curr.nlist.n_value - sect.addr;
- const end_addr = if (next) |n| n.nlist.n_value - sect.addr else sect.size;
+ // Bubble-up senior symbol as the main link to the text block.
+ for (nlist_indices.items) |*index| {
+ const sym = self.symbols.items[index.*];
+ if (sym.payload != .regular) {
+ log.err("expected a regular symbol, found {s}", .{sym.payload});
+ log.err(" when remapping {s}", .{sym.name});
+ return error.SymbolIsNotRegular;
+ }
+ assert(sym.payload.regular.local_sym_index != 0); // This means the symbol has not been properly resolved.
+ index.* = sym.payload.regular.local_sym_index;
+ }
- const tb_code = code[start_addr..end_addr];
- const size = tb_code.len;
+ std.sort.sort(u32, nlist_indices.items, SeniorityContext{ .zld = zld }, cmpSymBySeniority);
- log.warn("TextBlock", .{});
- for (indices.items) |id| {
- const sym = self.symbols.items[syms[id].index];
- log.warn(" | symbol = {s}", .{sym.name});
- }
- log.warn(" | start_addr = {}", .{start_addr});
- log.warn(" | end_addr = {}", .{end_addr});
- log.warn(" | size = {}", .{size});
- log.warn(" | alignment = 0x{x}", .{alignment});
- log.warn(" | segment_id = {}", .{match.seg});
- log.warn(" | section_id = {}", .{match.sect});
- log.warn(" | relocs: {any}", .{SymWithIndex.filterRelocs(relocs, start_addr, end_addr)});
-
- indices.clearRetainingCapacity();
- }
- } else {
- return error.TODOOneLargeTextBlock;
- }
- }
-}
+ const local_sym_index = nlist_indices.pop();
+ const sym = zld.locals.items[local_sym_index];
+ if (sym.payload.regular.file) |file| {
+ if (file != self) {
+ log.warn("deduping definition of {s} in {s}", .{ sym.name, self.name.? });
+ continue;
+ }
+ }
-const SectionAsTextBlocksArgs = struct {
- sect: macho.section_64,
- code: []u8,
- subsections_via_symbols: bool = false,
- relocs: ?[]macho.relocation_info = null,
- segment_id: u16 = 0,
- section_id: u16 = 0,
-};
+ const start_addr = curr.nlist.n_value - sect.addr;
+ const end_addr = if (next) |n| n.nlist.n_value - sect.addr else sect.size;
+
+ const tb_code = code[start_addr..end_addr];
+ const size = tb_code.len;
+
+ const block = try self.allocator.create(TextBlock);
+ errdefer self.allocator.destroy(block);
+
+ block.* = .{
+ .local_sym_index = local_sym_index,
+ .aliases = std.ArrayList(u32).init(self.allocator),
+ .references = std.ArrayList(u32).init(self.allocator),
+ .code = tb_code,
+ .relocs = std.ArrayList(*Relocation).init(self.allocator),
+ .size = size,
+ .alignment = alignment,
+ .segment_id = match.seg,
+ .section_id = match.sect,
+ };
+ try block.aliases.appendSlice(nlist_indices.items);
+
+ // TODO parse relocs
+
+ if (last_block) |last| {
+ last.next = block;
+ block.prev = last;
+ }
+ last_block = block;
-fn sectionAsTextBlocks(self: *Object, args: SectionAsTextBlocksArgs) !*TextBlock {
- const sect = args.sect;
+ nlist_indices.clearRetainingCapacity();
+ }
- log.warn("putting section '{s},{s}' as a TextBlock", .{ segmentName(sect), sectionName(sect) });
+ break :next;
+ }
- // Section alignment will be the assumed alignment per symbol.
- const alignment = sect.@"align";
+ // Since there is no symbol to refer to this block, we create
+ // a temp one.
+ const name = try std.fmt.allocPrint(self.allocator, "l_{s}_{s}_{s}", .{
+ self.name.?,
+ segmentName(sect),
+ sectionName(sect),
+ });
+ defer self.allocator.free(name);
+ const symbol = try Symbol.new(self.allocator, name);
+ symbol.payload = .{
+ .regular = .{
+ .linkage = .translation_unit,
+ .file = self,
+ },
+ };
+ const local_sym_index = @intCast(u32, zld.locals.items.len);
+ try zld.locals.append(zld.allocator, symbol);
- const first_block: *TextBlock = blk: {
- if (args.subsections_via_symbols) {
- return error.TODO;
- } else {
const block = try self.allocator.create(TextBlock);
errdefer self.allocator.destroy(block);
block.* = .{
- .ref = .{
- .section = undefined, // Will be populated when we allocated final sections.
- },
- .code = args.code,
- .relocs = null,
+ .local_sym_index = local_sym_index,
+ .aliases = std.ArrayList(u32).init(self.allocator),
+ .references = std.ArrayList(u32).init(self.allocator),
+ .code = code,
+ .relocs = std.ArrayList(*Relocation).init(self.allocator),
.size = sect.size,
.alignment = alignment,
- .segment_id = args.segment_id,
- .section_id = args.section_id,
+ .segment_id = match.seg,
+ .section_id = match.sect,
};
// TODO parse relocs
- if (args.relocs) |relocs| {
- block.relocs = try reloc.parse(self.allocator, self.arch.?, args.code, relocs, symbols);
- }
- break :blk block;
+ if (last_block) |last| {
+ last.next = block;
+ block.prev = last;
+ }
+ last_block = block;
}
- };
+ }
- return first_block;
+ return last_block;
}
pub fn parseInitializers(self: *Object) !void {
src/link/MachO/Symbol.zig
@@ -40,10 +40,13 @@ pub const Regular = struct {
linkage: Linkage,
/// Symbol address.
- address: u64,
+ address: u64 = 0,
- /// Section ID where the symbol resides.
- section: u8,
+ /// Segment ID
+ segment_id: u16 = 0,
+
+ /// Section ID
+ section: u16 = 0,
/// Whether the symbol is a weak ref.
weak_ref: bool = false,
@@ -52,6 +55,8 @@ pub const Regular = struct {
/// null means self-reference.
file: ?*Object = null,
+ local_sym_index: u32 = 0,
+
pub const Linkage = enum {
translation_unit,
linkage_unit,
src/link/MachO/Zld.zig
@@ -104,6 +104,7 @@ objc_classrefs_section_index: ?u16 = null,
objc_data_section_index: ?u16 = null,
locals: std.ArrayListUnmanaged(*Symbol) = .{},
+imports: std.ArrayListUnmanaged(*Symbol) = .{},
globals: std.StringArrayHashMapUnmanaged(*Symbol) = .{},
/// Offset into __DATA,__common section.
@@ -118,6 +119,8 @@ got_entries: std.ArrayListUnmanaged(*Symbol) = .{},
stub_helper_stubs_start_off: ?u64 = null,
+last_text_block: ?*TextBlock = null,
+
pub const Output = struct {
tag: enum { exe, dylib },
path: []const u8,
@@ -135,12 +138,11 @@ const TlvOffset = struct {
};
pub const TextBlock = struct {
- allocator: *Allocator,
local_sym_index: u32,
aliases: std.ArrayList(u32),
references: std.ArrayList(u32),
code: []u8,
- relocs: ?std.ArrayList(*Relocation) = null,
+ relocs: std.ArrayList(*Relocation),
size: u64,
alignment: u32,
segment_id: u16,
@@ -151,14 +153,33 @@ pub const TextBlock = struct {
pub fn deinit(block: *TextBlock, allocator: *Allocator) void {
block.aliases.deinit();
block.references.deinit();
- if (block.relocs) |relocs| {
- for (relocs.items) |reloc| {
- allocator.destroy(reloc);
- }
- relocs.deinit();
+ for (block.relocs.items) |reloc| {
+ allocator.destroy(reloc);
}
+ block.relocs.deinit();
allocator.free(code);
}
+
+ fn print(self: *const TextBlock, zld: *Zld) void {
+ if (self.prev) |prev| {
+ prev.print(zld);
+ }
+
+ log.warn("TextBlock", .{});
+ log.warn(" | {}: '{s}'", .{ self.local_sym_index, zld.locals.items[self.local_sym_index].name });
+ log.warn(" | Aliases:", .{});
+ for (self.aliases.items) |index| {
+ log.warn(" | {}: '{s}'", .{ index, zld.locals.items[index].name });
+ }
+ log.warn(" | References:", .{});
+ for (self.references.items) |index| {
+ log.warn(" | {}: '{s}'", .{ index, zld.locals.items[index].name });
+ }
+ log.warn(" | size = {}", .{self.size});
+ log.warn(" | align = {}", .{self.alignment});
+ log.warn(" | segment_id = {}", .{self.segment_id});
+ log.warn(" | section_id = {}", .{self.section_id});
+ }
};
/// Default path to dyld
@@ -200,11 +221,13 @@ pub fn deinit(self: *Zld) void {
}
self.dylibs.deinit(self.allocator);
- for (self.globals.values()) |sym| {
+ self.globals.deinit(self.allocator);
+
+ for (self.imports.items) |sym| {
sym.deinit(self.allocator);
self.allocator.destroy(sym);
}
- self.globals.deinit(self.allocator);
+ self.imports.deinit(self.allocator);
for (self.locals.items) |sym| {
sym.deinit(self.allocator);
@@ -252,20 +275,21 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg
try self.parseLibs(args.libs, args.syslibroot);
try self.resolveSymbols();
try self.parseTextBlocks();
- try self.resolveStubsAndGotEntries();
- try self.updateMetadata();
- try self.sortSections();
- try self.addRpaths(args.rpaths);
- try self.addDataInCodeLC();
- try self.addCodeSignatureLC();
- try self.allocateTextSegment();
- try self.allocateDataConstSegment();
- try self.allocateDataSegment();
- self.allocateLinkeditSegment();
- try self.allocateSymbols();
- try self.allocateTentativeSymbols();
- try self.allocateProxyBindAddresses();
- try self.flush();
+ return error.TODO;
+ // try self.resolveStubsAndGotEntries();
+ // try self.updateMetadata();
+ // try self.sortSections();
+ // try self.addRpaths(args.rpaths);
+ // try self.addDataInCodeLC();
+ // try self.addCodeSignatureLC();
+ // try self.allocateTextSegment();
+ // try self.allocateDataConstSegment();
+ // try self.allocateDataSegment();
+ // self.allocateLinkeditSegment();
+ // try self.allocateSymbols();
+ // try self.allocateTentativeSymbols();
+ // try self.allocateProxyBindAddresses();
+ // try self.flush();
}
fn parseInputFiles(self: *Zld, files: []const []const u8, syslibroot: ?[]const u8) !void {
@@ -1509,13 +1533,11 @@ fn resolveSymbolsInObject(self: *Zld, object: *Object) !void {
symbol.payload = .{
.regular = .{
.linkage = .translation_unit,
- .address = sym.n_value,
- .section = sym.n_sect - 1,
.weak_ref = Symbol.isWeakRef(sym),
.file = object,
+ .local_sym_index = @intCast(u32, self.locals.items.len),
},
};
- const index = @intCast(u32, self.locals.items.len);
try self.locals.append(self.allocator, symbol);
try object.symbols.append(self.allocator, symbol);
continue;
@@ -1550,8 +1572,6 @@ fn resolveSymbolsInObject(self: *Zld, object: *Object) !void {
symbol.payload = .{
.regular = .{
.linkage = linkage,
- .address = sym.n_value,
- .section = sym.n_sect - 1,
.weak_ref = Symbol.isWeakRef(sym),
.file = object,
},
@@ -1581,6 +1601,11 @@ fn resolveSymbolsInObject(self: *Zld, object: *Object) !void {
}
fn resolveSymbols(self: *Zld) !void {
+ // TODO mimicking insertion of null symbol from incremental linker.
+ // This will need to moved.
+ const null_sym = try Symbol.new(self.allocator, "");
+ try self.locals.append(self.allocator, null_sym);
+
// First pass, resolve symbols in provided objects.
for (self.objects.items) |object| {
try self.resolveSymbolsInObject(object);
@@ -1609,11 +1634,18 @@ fn resolveSymbols(self: *Zld) !void {
}
}
+ // Put any globally defined regular symbol as local.
// Mark if we need to allocate zerofill section for tentative definitions
for (self.globals.values()) |symbol| {
- if (symbol.payload == .tentative) {
- self.has_tentative_defs = true;
- break;
+ switch (symbol.payload) {
+ .regular => |*reg| {
+ reg.local_sym_index = @intCast(u32, self.locals.items.len);
+ try self.locals.append(self.allocator, symbol);
+ },
+ .tentative => {
+ self.has_tentative_defs = true;
+ },
+ else => {},
}
}
@@ -1639,6 +1671,7 @@ fn resolveSymbols(self: *Zld) !void {
.file = dylib,
},
};
+ try self.imports.append(self.allocator, symbol);
continue :loop;
}
}
@@ -1667,6 +1700,7 @@ fn resolveSymbols(self: *Zld) !void {
symbol.payload = .{
.proxy = .{},
};
+ try self.imports.append(self.allocator, symbol);
}
}
@@ -1686,7 +1720,17 @@ fn resolveSymbols(self: *Zld) !void {
fn parseTextBlocks(self: *Zld) !void {
for (self.objects.items) |object| {
- _ = try object.parseTextBlocks(self);
+ if (try object.parseTextBlocks(self)) |block| {
+ if (self.last_text_block) |last| {
+ last.next = block;
+ block.prev = last;
+ }
+ self.last_text_block = block;
+ }
+ }
+
+ if (self.last_text_block) |block| {
+ block.print(self);
}
}