mirror of
https://github.com/ziglang/zig.git
synced 2025-01-19 16:31:52 +00:00
zld: replace parsed reloc with a simple wrapper around macho.relocation_info
This commit is contained in:
parent
5a2bea2931
commit
54a403d4ff
@ -581,7 +581,6 @@ set(ZIG_STAGE2_SOURCES
|
||||
"${CMAKE_SOURCE_DIR}/src/link/MachO/DebugSymbols.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/link/MachO/Dylib.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/link/MachO/Object.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/link/MachO/Symbol.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/link/MachO/TextBlock.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/link/MachO/Trie.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/link/MachO/Zld.zig"
|
||||
|
@ -12,8 +12,8 @@ const fat = @import("fat.zig");
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const Arch = std.Target.Cpu.Arch;
|
||||
const Symbol = @import("Symbol.zig");
|
||||
const LibStub = @import("../tapi.zig").LibStub;
|
||||
const Zld = @import("Zld.zig");
|
||||
|
||||
usingnamespace @import("commands.zig");
|
||||
|
||||
@ -324,7 +324,7 @@ fn parseSymbols(self: *Dylib) !void {
|
||||
_ = try self.file.?.preadAll(strtab, symtab_cmd.stroff + self.library_offset);
|
||||
|
||||
for (slice) |sym| {
|
||||
const add_to_symtab = Symbol.isExt(sym) and (Symbol.isSect(sym) or Symbol.isIndr(sym));
|
||||
const add_to_symtab = Zld.symbolIsExt(sym) and (Zld.symbolIsSect(sym) or Zld.symbolIsIndr(sym));
|
||||
|
||||
if (!add_to_symtab) continue;
|
||||
|
||||
|
@ -9,13 +9,10 @@ const log = std.log.scoped(.object);
|
||||
const macho = std.macho;
|
||||
const math = std.math;
|
||||
const mem = std.mem;
|
||||
const reloc = @import("reloc.zig");
|
||||
const sort = std.sort;
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const Arch = std.Target.Cpu.Arch;
|
||||
const Relocation = reloc.Relocation;
|
||||
const Symbol = @import("Symbol.zig");
|
||||
const TextBlock = @import("TextBlock.zig");
|
||||
const Zld = @import("Zld.zig");
|
||||
|
||||
@ -57,6 +54,8 @@ tu_comp_dir: ?[]const u8 = null,
|
||||
mtime: ?u64 = null,
|
||||
|
||||
text_blocks: std.ArrayListUnmanaged(*TextBlock) = .{},
|
||||
sections_as_symbols: std.AutoHashMapUnmanaged(u16, u32) = .{},
|
||||
symbol_mapping: std.AutoHashMapUnmanaged(u32, u32) = .{},
|
||||
|
||||
const DebugInfo = struct {
|
||||
inner: dwarf.DwarfInfo,
|
||||
@ -163,6 +162,8 @@ pub fn deinit(self: *Object) void {
|
||||
self.symtab.deinit(self.allocator);
|
||||
self.strtab.deinit(self.allocator);
|
||||
self.text_blocks.deinit(self.allocator);
|
||||
self.sections_as_symbols.deinit(self.allocator);
|
||||
self.symbol_mapping.deinit(self.allocator);
|
||||
|
||||
if (self.debug_info) |*db| {
|
||||
db.deinit(self.allocator);
|
||||
@ -372,20 +373,17 @@ const TextBlockParser = struct {
|
||||
}
|
||||
|
||||
const SeniorityContext = struct {
|
||||
zld: *Zld,
|
||||
object: *Object,
|
||||
};
|
||||
|
||||
fn lessThanBySeniority(context: SeniorityContext, lhs: NlistWithIndex, rhs: NlistWithIndex) bool {
|
||||
const lsym = context.zld.locals.items[lhs.index];
|
||||
const rsym = context.zld.locals.items[rhs.index];
|
||||
const lreg = lsym.payload.regular;
|
||||
const rreg = rsym.payload.regular;
|
||||
|
||||
return switch (rreg.linkage) {
|
||||
.global => true,
|
||||
.linkage_unit => lreg.linkage == .translation_unit,
|
||||
else => lsym.isTemp(context.zld),
|
||||
};
|
||||
if (!Zld.symbolIsExt(rhs.nlist)) {
|
||||
return Zld.symbolIsTemp(lhs.nlist, context.object.getString(lhs.nlist.n_strx));
|
||||
} else if (Zld.symbolIsPext(rhs.nlist) or Zld.symbolIsWeakDef(rhs.nlist)) {
|
||||
return !Zld.symbolIsExt(lhs.nlist);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn next(self: *TextBlockParser) !?*TextBlock {
|
||||
@ -409,6 +407,7 @@ const TextBlockParser = struct {
|
||||
} else null;
|
||||
|
||||
for (aliases.items) |*nlist_with_index| {
|
||||
nlist_with_index.index = self.symbol_mapping.get(nlist_with_index.index);
|
||||
const sym = self.object.symbols.items[nlist_with_index.index];
|
||||
if (sym.payload != .regular) {
|
||||
log.err("expected a regular symbol, found {s}", .{sym.payload});
|
||||
@ -424,7 +423,7 @@ const TextBlockParser = struct {
|
||||
sort.sort(
|
||||
NlistWithIndex,
|
||||
aliases.items,
|
||||
SeniorityContext{ .zld = self.zld },
|
||||
SeniorityContext{ .object = self.object },
|
||||
@This().lessThanBySeniority,
|
||||
);
|
||||
}
|
||||
@ -515,7 +514,7 @@ const TextBlockParser = struct {
|
||||
pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
|
||||
const seg = self.load_commands.items[self.segment_cmd_index.?].Segment;
|
||||
|
||||
log.debug("analysing {s}", .{self.name.?});
|
||||
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.
|
||||
@ -536,14 +535,14 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
|
||||
|
||||
for (seg.sections.items) |sect, id| {
|
||||
const sect_id = @intCast(u8, id);
|
||||
log.debug("putting section '{s},{s}' as a TextBlock", .{
|
||||
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.debug("unhandled section", .{});
|
||||
log.warn("unhandled section", .{});
|
||||
continue;
|
||||
};
|
||||
|
||||
@ -577,200 +576,249 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
|
||||
};
|
||||
zld.has_stabs = zld.has_stabs or self.debug_info != null;
|
||||
|
||||
next: {
|
||||
if (is_splittable) blocks: {
|
||||
if (filtered_nlists.len == 0) break :blocks;
|
||||
{
|
||||
// next: {
|
||||
// if (is_splittable) blocks: {
|
||||
// if (filtered_nlists.len == 0) break :blocks;
|
||||
|
||||
// If the first nlist does not match the start of the section,
|
||||
// then we need encapsulate the memory range [section start, first symbol)
|
||||
// as a temporary symbol and insert the matching TextBlock.
|
||||
const first_nlist = filtered_nlists[0].nlist;
|
||||
if (first_nlist.n_value > sect.addr) {
|
||||
const symbol = self.sections_as_symbols.get(sect_id) orelse symbol: {
|
||||
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 zld.allocator.create(Symbol);
|
||||
symbol.* = .{
|
||||
.strx = try zld.makeString(name),
|
||||
.payload = .{ .undef = .{} },
|
||||
};
|
||||
try self.sections_as_symbols.putNoClobber(self.allocator, sect_id, symbol);
|
||||
break :symbol symbol;
|
||||
};
|
||||
// // If the first nlist does not match the start of the section,
|
||||
// // then we need encapsulate the memory range [section start, first symbol)
|
||||
// // as a temporary symbol and insert the matching TextBlock.
|
||||
// const first_nlist = filtered_nlists[0].nlist;
|
||||
// if (first_nlist.n_value > sect.addr) {
|
||||
// const symbol = self.sections_as_symbols.get(sect_id) orelse symbol: {
|
||||
// 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 zld.allocator.create(Symbol);
|
||||
// symbol.* = .{
|
||||
// .strx = try zld.makeString(name),
|
||||
// .payload = .{ .undef = .{} },
|
||||
// };
|
||||
// try self.sections_as_symbols.putNoClobber(self.allocator, sect_id, symbol);
|
||||
// break :symbol symbol;
|
||||
// };
|
||||
|
||||
const local_sym_index = @intCast(u32, zld.locals.items.len);
|
||||
symbol.payload = .{
|
||||
.regular = .{
|
||||
.linkage = .translation_unit,
|
||||
.address = sect.addr,
|
||||
.segment_id = match.seg,
|
||||
.section_id = match.sect,
|
||||
.file = self,
|
||||
.local_sym_index = local_sym_index,
|
||||
},
|
||||
};
|
||||
try zld.locals.append(zld.allocator, symbol);
|
||||
// const local_sym_index = @intCast(u32, zld.locals.items.len);
|
||||
// symbol.payload = .{
|
||||
// .regular = .{
|
||||
// .linkage = .translation_unit,
|
||||
// .address = sect.addr,
|
||||
// .segment_id = match.seg,
|
||||
// .section_id = match.sect,
|
||||
// .file = self,
|
||||
// .local_sym_index = local_sym_index,
|
||||
// },
|
||||
// };
|
||||
// try zld.locals.append(zld.allocator, symbol);
|
||||
|
||||
const block_code = code[0 .. first_nlist.n_value - sect.addr];
|
||||
const block_size = block_code.len;
|
||||
// const block_code = code[0 .. first_nlist.n_value - sect.addr];
|
||||
// const block_size = block_code.len;
|
||||
|
||||
const block = try self.allocator.create(TextBlock);
|
||||
errdefer self.allocator.destroy(block);
|
||||
// const block = try self.allocator.create(TextBlock);
|
||||
// errdefer self.allocator.destroy(block);
|
||||
|
||||
block.* = TextBlock.init(self.allocator);
|
||||
block.local_sym_index = local_sym_index;
|
||||
block.code = try self.allocator.dupe(u8, block_code);
|
||||
block.size = block_size;
|
||||
block.alignment = sect.@"align";
|
||||
// block.* = TextBlock.init(self.allocator);
|
||||
// block.local_sym_index = local_sym_index;
|
||||
// block.code = try self.allocator.dupe(u8, block_code);
|
||||
// block.size = block_size;
|
||||
// block.alignment = sect.@"align";
|
||||
|
||||
const block_relocs = filterRelocs(relocs, 0, block_size);
|
||||
if (block_relocs.len > 0) {
|
||||
try self.parseRelocs(zld, block_relocs, block, 0);
|
||||
}
|
||||
// const block_relocs = filterRelocs(relocs, 0, block_size);
|
||||
// if (block_relocs.len > 0) {
|
||||
// try self.parseRelocs(zld, block_relocs, block, 0);
|
||||
// }
|
||||
|
||||
if (zld.has_dices) {
|
||||
const dices = filterDice(self.data_in_code_entries.items, sect.addr, sect.addr + block_size);
|
||||
try block.dices.ensureTotalCapacity(dices.len);
|
||||
// if (zld.has_dices) {
|
||||
// const dices = filterDice(self.data_in_code_entries.items, sect.addr, sect.addr + block_size);
|
||||
// try block.dices.ensureTotalCapacity(dices.len);
|
||||
|
||||
for (dices) |dice| {
|
||||
block.dices.appendAssumeCapacity(.{
|
||||
.offset = dice.offset - try math.cast(u32, sect.addr),
|
||||
.length = dice.length,
|
||||
.kind = dice.kind,
|
||||
});
|
||||
}
|
||||
}
|
||||
// for (dices) |dice| {
|
||||
// block.dices.appendAssumeCapacity(.{
|
||||
// .offset = dice.offset - try math.cast(u32, sect.addr),
|
||||
// .length = dice.length,
|
||||
// .kind = dice.kind,
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
|
||||
// Update target section's metadata
|
||||
// TODO should we update segment's size here too?
|
||||
// How does it tie with incremental space allocs?
|
||||
const tseg = &zld.load_commands.items[match.seg].Segment;
|
||||
const tsect = &tseg.sections.items[match.sect];
|
||||
const new_alignment = math.max(tsect.@"align", block.alignment);
|
||||
const new_alignment_pow_2 = try math.powi(u32, 2, new_alignment);
|
||||
const new_size = mem.alignForwardGeneric(u64, tsect.size, new_alignment_pow_2) + block.size;
|
||||
tsect.size = new_size;
|
||||
tsect.@"align" = new_alignment;
|
||||
// // Update target section's metadata
|
||||
// // TODO should we update segment's size here too?
|
||||
// // How does it tie with incremental space allocs?
|
||||
// const tseg = &zld.load_commands.items[match.seg].Segment;
|
||||
// const tsect = &tseg.sections.items[match.sect];
|
||||
// const new_alignment = math.max(tsect.@"align", block.alignment);
|
||||
// const new_alignment_pow_2 = try math.powi(u32, 2, new_alignment);
|
||||
// const new_size = mem.alignForwardGeneric(u64, tsect.size, new_alignment_pow_2) + block.size;
|
||||
// tsect.size = new_size;
|
||||
// tsect.@"align" = new_alignment;
|
||||
|
||||
if (zld.blocks.getPtr(match)) |last| {
|
||||
last.*.next = block;
|
||||
block.prev = last.*;
|
||||
last.* = block;
|
||||
} else {
|
||||
try zld.blocks.putNoClobber(zld.allocator, match, block);
|
||||
}
|
||||
// if (zld.blocks.getPtr(match)) |last| {
|
||||
// last.*.next = block;
|
||||
// block.prev = last.*;
|
||||
// last.* = block;
|
||||
// } else {
|
||||
// try zld.blocks.putNoClobber(zld.allocator, match, block);
|
||||
// }
|
||||
|
||||
try self.text_blocks.append(self.allocator, block);
|
||||
}
|
||||
// try self.text_blocks.append(self.allocator, block);
|
||||
// }
|
||||
|
||||
var parser = TextBlockParser{
|
||||
.allocator = self.allocator,
|
||||
.section = sect,
|
||||
.code = code,
|
||||
.relocs = relocs,
|
||||
.object = self,
|
||||
.zld = zld,
|
||||
.nlists = filtered_nlists,
|
||||
.match = match,
|
||||
};
|
||||
// var parser = TextBlockParser{
|
||||
// .allocator = self.allocator,
|
||||
// .section = sect,
|
||||
// .code = code,
|
||||
// .relocs = relocs,
|
||||
// .object = self,
|
||||
// .zld = zld,
|
||||
// .nlists = filtered_nlists,
|
||||
// .match = match,
|
||||
// };
|
||||
|
||||
while (try parser.next()) |block| {
|
||||
const sym = zld.locals.items[block.local_sym_index];
|
||||
const reg = &sym.payload.regular;
|
||||
if (reg.file) |file| {
|
||||
if (file != self) {
|
||||
log.debug("deduping definition of {s} in {s}", .{ zld.getString(sym.strx), self.name.? });
|
||||
block.deinit();
|
||||
self.allocator.destroy(block);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// while (try parser.next()) |block| {
|
||||
// const sym = zld.locals.items[block.local_sym_index];
|
||||
// const reg = &sym.payload.regular;
|
||||
// if (reg.file) |file| {
|
||||
// if (file != self) {
|
||||
// log.debug("deduping definition of {s} in {s}", .{ zld.getString(sym.strx), self.name.? });
|
||||
// block.deinit();
|
||||
// self.allocator.destroy(block);
|
||||
// continue;
|
||||
// }
|
||||
// }
|
||||
|
||||
if (reg.address == sect.addr) {
|
||||
if (self.sections_as_symbols.get(sect_id)) |alias| {
|
||||
// Add alias.
|
||||
const local_sym_index = @intCast(u32, zld.locals.items.len);
|
||||
const reg_alias = &alias.payload.regular;
|
||||
reg_alias.segment_id = match.seg;
|
||||
reg_alias.section_id = match.sect;
|
||||
reg_alias.local_sym_index = local_sym_index;
|
||||
try block.aliases.append(local_sym_index);
|
||||
try zld.locals.append(zld.allocator, alias);
|
||||
}
|
||||
}
|
||||
// if (reg.address == sect.addr) {
|
||||
// if (self.sections_as_symbols.get(sect_id)) |alias| {
|
||||
// // Add alias.
|
||||
// const local_sym_index = @intCast(u32, zld.locals.items.len);
|
||||
// const reg_alias = &alias.payload.regular;
|
||||
// reg_alias.segment_id = match.seg;
|
||||
// reg_alias.section_id = match.sect;
|
||||
// reg_alias.local_sym_index = local_sym_index;
|
||||
// try block.aliases.append(local_sym_index);
|
||||
// try zld.locals.append(zld.allocator, alias);
|
||||
// }
|
||||
// }
|
||||
|
||||
// Update target section's metadata
|
||||
// TODO should we update segment's size here too?
|
||||
// How does it tie with incremental space allocs?
|
||||
const tseg = &zld.load_commands.items[match.seg].Segment;
|
||||
const tsect = &tseg.sections.items[match.sect];
|
||||
const new_alignment = math.max(tsect.@"align", block.alignment);
|
||||
const new_alignment_pow_2 = try math.powi(u32, 2, new_alignment);
|
||||
const new_size = mem.alignForwardGeneric(u64, tsect.size, new_alignment_pow_2) + block.size;
|
||||
tsect.size = new_size;
|
||||
tsect.@"align" = new_alignment;
|
||||
// // Update target section's metadata
|
||||
// // TODO should we update segment's size here too?
|
||||
// // How does it tie with incremental space allocs?
|
||||
// const tseg = &zld.load_commands.items[match.seg].Segment;
|
||||
// const tsect = &tseg.sections.items[match.sect];
|
||||
// const new_alignment = math.max(tsect.@"align", block.alignment);
|
||||
// const new_alignment_pow_2 = try math.powi(u32, 2, new_alignment);
|
||||
// const new_size = mem.alignForwardGeneric(u64, tsect.size, new_alignment_pow_2) + block.size;
|
||||
// tsect.size = new_size;
|
||||
// tsect.@"align" = new_alignment;
|
||||
|
||||
if (zld.blocks.getPtr(match)) |last| {
|
||||
last.*.next = block;
|
||||
block.prev = last.*;
|
||||
last.* = block;
|
||||
} else {
|
||||
try zld.blocks.putNoClobber(zld.allocator, match, block);
|
||||
}
|
||||
// if (zld.blocks.getPtr(match)) |last| {
|
||||
// last.*.next = block;
|
||||
// block.prev = last.*;
|
||||
// last.* = block;
|
||||
// } else {
|
||||
// try zld.blocks.putNoClobber(zld.allocator, match, block);
|
||||
// }
|
||||
|
||||
try self.text_blocks.append(self.allocator, block);
|
||||
}
|
||||
// try self.text_blocks.append(self.allocator, block);
|
||||
// }
|
||||
|
||||
break :next;
|
||||
}
|
||||
// break :next;
|
||||
// }
|
||||
|
||||
// Since there is no symbol to refer to this block, we create
|
||||
// a temp one, unless we already did that when working out the relocations
|
||||
// of other text blocks.
|
||||
const symbol = self.sections_as_symbols.get(sect_id) orelse symbol: {
|
||||
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 zld.allocator.create(Symbol);
|
||||
symbol.* = .{
|
||||
.strx = try zld.makeString(name),
|
||||
.payload = .{ .undef = .{} },
|
||||
};
|
||||
try self.sections_as_symbols.putNoClobber(self.allocator, sect_id, symbol);
|
||||
break :symbol symbol;
|
||||
};
|
||||
|
||||
const local_sym_index = @intCast(u32, zld.locals.items.len);
|
||||
symbol.payload = .{
|
||||
.regular = .{
|
||||
.linkage = .translation_unit,
|
||||
.address = sect.addr,
|
||||
.segment_id = match.seg,
|
||||
.section_id = match.sect,
|
||||
.file = self,
|
||||
.local_sym_index = local_sym_index,
|
||||
},
|
||||
};
|
||||
try zld.locals.append(zld.allocator, symbol);
|
||||
const block_local_sym_index = @intCast(u32, zld.locals.items.len);
|
||||
const sym_name = try std.fmt.allocPrint(self.allocator, "l_{s}_{s}_{s}", .{
|
||||
self.name.?,
|
||||
segmentName(sect),
|
||||
sectionName(sect),
|
||||
});
|
||||
defer self.allocator.free(sym_name);
|
||||
try zld.locals.append(zld.allocator, .{
|
||||
.n_strx = try zld.makeString(sym_name),
|
||||
.n_type = macho.N_SECT,
|
||||
.n_sect = zld.sectionId(match),
|
||||
.n_desc = 0,
|
||||
.n_value = sect.addr,
|
||||
});
|
||||
const block_local = &zld.locals.items[block_local_sym_index];
|
||||
block_local.n_sect = zld.sectionId(match);
|
||||
|
||||
const block = try self.allocator.create(TextBlock);
|
||||
errdefer self.allocator.destroy(block);
|
||||
|
||||
block.* = TextBlock.init(self.allocator);
|
||||
block.local_sym_index = local_sym_index;
|
||||
block.local_sym_index = block_local_sym_index;
|
||||
block.code = try self.allocator.dupe(u8, code);
|
||||
block.size = sect.size;
|
||||
block.alignment = sect.@"align";
|
||||
|
||||
if (relocs.len > 0) {
|
||||
try self.parseRelocs(zld, relocs, block, 0);
|
||||
try block.relocs.ensureTotalCapacity(relocs.len);
|
||||
for (relocs) |rel| {
|
||||
const out_rel: TextBlock.Relocation = outer: {
|
||||
if (rel.r_extern == 0) {
|
||||
const rel_sect_id = @intCast(u16, rel.r_symbolnum - 1);
|
||||
const sect_sym_index = self.sections_as_symbols.get(rel_sect_id) orelse blk: {
|
||||
const sect_sym_index = @intCast(u32, zld.locals.items.len);
|
||||
const sect_sym_name = try std.fmt.allocPrint(self.allocator, "l_{s}_{s}_{s}", .{
|
||||
self.name.?,
|
||||
segmentName(sect),
|
||||
sectionName(sect),
|
||||
});
|
||||
defer self.allocator.free(sect_sym_name);
|
||||
try zld.locals.append(zld.allocator, .{
|
||||
.n_strx = try zld.makeString(sect_sym_name),
|
||||
.n_type = macho.N_SECT,
|
||||
.n_sect = 0,
|
||||
.n_desc = 0,
|
||||
.n_value = 0,
|
||||
});
|
||||
try self.sections_as_symbols.putNoClobber(self.allocator, rel_sect_id, sect_sym_index);
|
||||
break :blk sect_sym_index;
|
||||
};
|
||||
break :outer .{
|
||||
.inner = rel,
|
||||
.where = .local,
|
||||
.where_index = sect_sym_index,
|
||||
};
|
||||
}
|
||||
|
||||
const rel_sym = self.symtab.items[rel.r_symbolnum];
|
||||
const rel_sym_name = self.getString(rel_sym.n_strx);
|
||||
|
||||
if (Zld.symbolIsSect(rel_sym) and !Zld.symbolIsExt(rel_sym)) {
|
||||
const where_index = self.symbol_mapping.get(rel.r_symbolnum) orelse unreachable;
|
||||
break :outer .{
|
||||
.inner = rel,
|
||||
.where = .local,
|
||||
.where_index = where_index,
|
||||
};
|
||||
}
|
||||
|
||||
const resolv = zld.symbol_resolver.get(rel_sym_name) orelse unreachable;
|
||||
switch (resolv.where) {
|
||||
.global => {
|
||||
break :outer .{
|
||||
.inner = rel,
|
||||
.where = .local,
|
||||
.where_index = resolv.local_sym_index,
|
||||
};
|
||||
},
|
||||
.import => {
|
||||
break :outer .{
|
||||
.inner = rel,
|
||||
.where = .import,
|
||||
.where_index = resolv.where_index,
|
||||
};
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
};
|
||||
block.relocs.appendAssumeCapacity(out_rel);
|
||||
}
|
||||
|
||||
if (zld.has_dices) {
|
||||
@ -791,44 +839,41 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
|
||||
// the filtered symbols and note which symbol is contained within so that
|
||||
// we can properly allocate addresses down the line.
|
||||
// While we're at it, we need to update segment,section mapping of each symbol too.
|
||||
if (filtered_nlists.len > 0) {
|
||||
var contained = std.ArrayList(TextBlock.SymbolAtOffset).init(self.allocator);
|
||||
defer contained.deinit();
|
||||
try contained.ensureTotalCapacity(filtered_nlists.len);
|
||||
var contained = std.ArrayList(TextBlock.SymbolAtOffset).init(self.allocator);
|
||||
defer contained.deinit();
|
||||
try contained.ensureTotalCapacity(filtered_nlists.len);
|
||||
|
||||
for (filtered_nlists) |nlist_with_index| {
|
||||
const sym = self.symbols.items[nlist_with_index.index];
|
||||
assert(sym.payload == .regular);
|
||||
const reg = &sym.payload.regular;
|
||||
for (filtered_nlists) |nlist_with_index| {
|
||||
const nlist = nlist_with_index.nlist;
|
||||
const local_sym_index = self.symbol_mapping.get(nlist_with_index.index) orelse unreachable;
|
||||
const local = &zld.locals.items[local_sym_index];
|
||||
local.n_sect = zld.sectionId(match);
|
||||
|
||||
reg.segment_id = match.seg;
|
||||
reg.section_id = match.sect;
|
||||
|
||||
const stab: ?TextBlock.Stab = if (self.debug_info) |di| blk: {
|
||||
// TODO there has to be a better to handle this.
|
||||
for (di.inner.func_list.items) |func| {
|
||||
if (func.pc_range) |range| {
|
||||
if (reg.address >= range.start and reg.address < range.end) {
|
||||
break :blk TextBlock.Stab{
|
||||
.function = range.end - range.start,
|
||||
};
|
||||
}
|
||||
const stab: ?TextBlock.Stab = if (self.debug_info) |di| blk: {
|
||||
// TODO there has to be a better to handle this.
|
||||
for (di.inner.func_list.items) |func| {
|
||||
if (func.pc_range) |range| {
|
||||
if (nlist.n_value >= range.start and nlist.n_value < range.end) {
|
||||
break :blk TextBlock.Stab{
|
||||
.function = range.end - range.start,
|
||||
};
|
||||
}
|
||||
}
|
||||
if (zld.globals.contains(zld.getString(sym.strx))) break :blk .global;
|
||||
break :blk .static;
|
||||
} else null;
|
||||
}
|
||||
// TODO
|
||||
// if (zld.globals.contains(zld.getString(sym.strx))) break :blk .global;
|
||||
break :blk .static;
|
||||
} else null;
|
||||
|
||||
contained.appendAssumeCapacity(.{
|
||||
.local_sym_index = reg.local_sym_index,
|
||||
.offset = nlist_with_index.nlist.n_value - sect.addr,
|
||||
.stab = stab,
|
||||
});
|
||||
}
|
||||
|
||||
block.contained = contained.toOwnedSlice();
|
||||
contained.appendAssumeCapacity(.{
|
||||
.local_sym_index = local_sym_index,
|
||||
.offset = nlist.n_value - sect.addr,
|
||||
.stab = stab,
|
||||
});
|
||||
}
|
||||
|
||||
block.contained = contained.toOwnedSlice();
|
||||
|
||||
// Update target section's metadata
|
||||
// TODO should we update segment's size here too?
|
||||
// How does it tie with incremental space allocs?
|
||||
@ -853,26 +898,6 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
|
||||
}
|
||||
}
|
||||
|
||||
fn parseRelocs(
|
||||
self: *Object,
|
||||
zld: *Zld,
|
||||
relocs: []const macho.relocation_info,
|
||||
block: *TextBlock,
|
||||
base_addr: u64,
|
||||
) !void {
|
||||
var it = reloc.RelocIterator{
|
||||
.buffer = relocs,
|
||||
};
|
||||
var parser = reloc.Parser{
|
||||
.object = self,
|
||||
.zld = zld,
|
||||
.it = &it,
|
||||
.block = block,
|
||||
.base_addr = base_addr,
|
||||
};
|
||||
try parser.parse();
|
||||
}
|
||||
|
||||
pub fn symbolFromReloc(self: *Object, zld: *Zld, rel: macho.relocation_info) !*Symbol {
|
||||
const symbol = blk: {
|
||||
if (rel.r_extern == 1) {
|
||||
|
@ -1,285 +0,0 @@
|
||||
const Symbol = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const commands = @import("commands.zig");
|
||||
const macho = std.macho;
|
||||
const mem = std.mem;
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const Dylib = @import("Dylib.zig");
|
||||
const Object = @import("Object.zig");
|
||||
const Zld = @import("Zld.zig");
|
||||
|
||||
/// Offset into the string table.
|
||||
strx: u32,
|
||||
|
||||
/// Index in GOT table for indirection.
|
||||
got_index: ?u32 = null,
|
||||
|
||||
/// Index in stubs table for late binding.
|
||||
stubs_index: ?u32 = null,
|
||||
|
||||
payload: union(enum) {
|
||||
regular: Regular,
|
||||
tentative: Tentative,
|
||||
proxy: Proxy,
|
||||
undef: Undefined,
|
||||
|
||||
pub fn format(self: @This(), comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
|
||||
return switch (self) {
|
||||
.regular => |p| p.format(fmt, options, writer),
|
||||
.tentative => |p| p.format(fmt, options, writer),
|
||||
.proxy => |p| p.format(fmt, options, writer),
|
||||
.undef => |p| p.format(fmt, options, writer),
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
pub const Regular = struct {
|
||||
/// Linkage type.
|
||||
linkage: Linkage,
|
||||
|
||||
/// Symbol address.
|
||||
address: u64 = 0,
|
||||
|
||||
/// Segment ID
|
||||
segment_id: u16 = 0,
|
||||
|
||||
/// Section ID
|
||||
section_id: u16 = 0,
|
||||
|
||||
/// Whether the symbol is a weak ref.
|
||||
weak_ref: bool = false,
|
||||
|
||||
/// Object file where to locate this symbol.
|
||||
/// null means self-reference.
|
||||
file: ?*Object = null,
|
||||
|
||||
local_sym_index: u32 = 0,
|
||||
|
||||
pub const Linkage = enum {
|
||||
translation_unit,
|
||||
linkage_unit,
|
||||
global,
|
||||
};
|
||||
|
||||
pub fn format(self: Regular, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
|
||||
_ = fmt;
|
||||
_ = options;
|
||||
try std.fmt.format(writer, "Regular {{ ", .{});
|
||||
try std.fmt.format(writer, ".linkage = {s}, ", .{self.linkage});
|
||||
try std.fmt.format(writer, ".address = 0x{x}, ", .{self.address});
|
||||
try std.fmt.format(writer, ".segment_id = {}, ", .{self.segment_id});
|
||||
try std.fmt.format(writer, ".section_id = {}, ", .{self.section_id});
|
||||
if (self.weak_ref) {
|
||||
try std.fmt.format(writer, ".weak_ref, ", .{});
|
||||
}
|
||||
if (self.file) |file| {
|
||||
try std.fmt.format(writer, ".file = {s}, ", .{file.name.?});
|
||||
}
|
||||
try std.fmt.format(writer, ".local_sym_index = {}, ", .{self.local_sym_index});
|
||||
try std.fmt.format(writer, "}}", .{});
|
||||
}
|
||||
|
||||
pub fn sectionId(self: Regular, zld: *Zld) u8 {
|
||||
// TODO there might be a more generic way of doing this.
|
||||
var section: u8 = 0;
|
||||
for (zld.load_commands.items) |cmd, cmd_id| {
|
||||
if (cmd != .Segment) break;
|
||||
if (cmd_id == self.segment_id) {
|
||||
section += @intCast(u8, self.section_id) + 1;
|
||||
break;
|
||||
}
|
||||
section += @intCast(u8, cmd.Segment.sections.items.len);
|
||||
}
|
||||
return section;
|
||||
}
|
||||
};
|
||||
|
||||
pub const Tentative = struct {
|
||||
/// Symbol size.
|
||||
size: u64,
|
||||
|
||||
/// Symbol alignment as power of two.
|
||||
alignment: u16,
|
||||
|
||||
/// File where this symbol was referenced.
|
||||
file: ?*Object = null,
|
||||
|
||||
pub fn format(self: Tentative, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
|
||||
_ = fmt;
|
||||
_ = options;
|
||||
try std.fmt.format(writer, "Tentative {{ ", .{});
|
||||
try std.fmt.format(writer, ".size = 0x{x}, ", .{self.size});
|
||||
try std.fmt.format(writer, ".alignment = 0x{x}, ", .{self.alignment});
|
||||
if (self.file) |file| {
|
||||
try std.fmt.format(writer, ".file = {s}, ", .{file.name.?});
|
||||
}
|
||||
try std.fmt.format(writer, "}}", .{});
|
||||
}
|
||||
};
|
||||
|
||||
pub const Proxy = struct {
|
||||
/// Dylib where to locate this symbol.
|
||||
/// null means self-reference.
|
||||
file: ?*Dylib = null,
|
||||
|
||||
local_sym_index: u32 = 0,
|
||||
|
||||
pub fn dylibOrdinal(proxy: Proxy) u16 {
|
||||
const dylib = proxy.file orelse return 0;
|
||||
return dylib.ordinal.?;
|
||||
}
|
||||
|
||||
pub fn format(self: Proxy, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
|
||||
_ = fmt;
|
||||
_ = options;
|
||||
try std.fmt.format(writer, "Proxy {{ ", .{});
|
||||
if (self.file) |file| {
|
||||
try std.fmt.format(writer, ".file = {s}, ", .{file.name.?});
|
||||
}
|
||||
try std.fmt.format(writer, ".local_sym_index = {d}, ", .{self.local_sym_index});
|
||||
try std.fmt.format(writer, "}}", .{});
|
||||
}
|
||||
};
|
||||
|
||||
pub const Undefined = struct {
|
||||
/// File where this symbol was referenced.
|
||||
/// null means synthetic, e.g., dyld_stub_binder.
|
||||
file: ?*Object = null,
|
||||
|
||||
pub fn format(self: Undefined, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
|
||||
_ = fmt;
|
||||
_ = options;
|
||||
try std.fmt.format(writer, "Undefined {{ ", .{});
|
||||
if (self.file) |file| {
|
||||
try std.fmt.format(writer, ".file = {s}, ", .{file.name.?});
|
||||
}
|
||||
try std.fmt.format(writer, "}}", .{});
|
||||
}
|
||||
};
|
||||
|
||||
pub fn format(self: Symbol, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
|
||||
_ = fmt;
|
||||
_ = options;
|
||||
try std.fmt.format(writer, "Symbol {{", .{});
|
||||
try std.fmt.format(writer, ".strx = {d}, ", .{self.strx});
|
||||
if (self.got_index) |got_index| {
|
||||
try std.fmt.format(writer, ".got_index = {}, ", .{got_index});
|
||||
}
|
||||
if (self.stubs_index) |stubs_index| {
|
||||
try std.fmt.format(writer, ".stubs_index = {}, ", .{stubs_index});
|
||||
}
|
||||
try std.fmt.format(writer, "{}, ", .{self.payload});
|
||||
try std.fmt.format(writer, "}}", .{});
|
||||
}
|
||||
|
||||
pub fn isTemp(symbol: Symbol, zld: *Zld) bool {
|
||||
const sym_name = zld.getString(symbol.strx);
|
||||
switch (symbol.payload) {
|
||||
.regular => |regular| {
|
||||
if (regular.linkage == .translation_unit) {
|
||||
return mem.startsWith(u8, sym_name, "l") or mem.startsWith(u8, sym_name, "L");
|
||||
}
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
pub fn asNlist(symbol: *Symbol, zld: *Zld) !macho.nlist_64 {
|
||||
const nlist = nlist: {
|
||||
switch (symbol.payload) {
|
||||
.regular => |regular| {
|
||||
var nlist = macho.nlist_64{
|
||||
.n_strx = symbol.strx,
|
||||
.n_type = macho.N_SECT,
|
||||
.n_sect = regular.sectionId(zld),
|
||||
.n_desc = 0,
|
||||
.n_value = regular.address,
|
||||
};
|
||||
|
||||
if (regular.linkage != .translation_unit) {
|
||||
nlist.n_type |= macho.N_EXT;
|
||||
}
|
||||
if (regular.linkage == .linkage_unit) {
|
||||
nlist.n_type |= macho.N_PEXT;
|
||||
nlist.n_desc |= macho.N_WEAK_DEF;
|
||||
}
|
||||
|
||||
break :nlist nlist;
|
||||
},
|
||||
.tentative => {
|
||||
// TODO
|
||||
break :nlist macho.nlist_64{
|
||||
.n_strx = symbol.strx,
|
||||
.n_type = macho.N_UNDF,
|
||||
.n_sect = 0,
|
||||
.n_desc = 0,
|
||||
.n_value = 0,
|
||||
};
|
||||
},
|
||||
.proxy => |proxy| {
|
||||
break :nlist macho.nlist_64{
|
||||
.n_strx = symbol.strx,
|
||||
.n_type = macho.N_UNDF | macho.N_EXT,
|
||||
.n_sect = 0,
|
||||
.n_desc = (proxy.dylibOrdinal() * macho.N_SYMBOL_RESOLVER) | macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY,
|
||||
.n_value = 0,
|
||||
};
|
||||
},
|
||||
.undef => {
|
||||
// TODO
|
||||
break :nlist macho.nlist_64{
|
||||
.n_strx = symbol.strx,
|
||||
.n_type = macho.N_UNDF,
|
||||
.n_sect = 0,
|
||||
.n_desc = 0,
|
||||
.n_value = 0,
|
||||
};
|
||||
},
|
||||
}
|
||||
};
|
||||
return nlist;
|
||||
}
|
||||
|
||||
pub fn isStab(sym: macho.nlist_64) bool {
|
||||
return (macho.N_STAB & sym.n_type) != 0;
|
||||
}
|
||||
|
||||
pub fn isPext(sym: macho.nlist_64) bool {
|
||||
return (macho.N_PEXT & sym.n_type) != 0;
|
||||
}
|
||||
|
||||
pub fn isExt(sym: macho.nlist_64) bool {
|
||||
return (macho.N_EXT & sym.n_type) != 0;
|
||||
}
|
||||
|
||||
pub fn isSect(sym: macho.nlist_64) bool {
|
||||
const type_ = macho.N_TYPE & sym.n_type;
|
||||
return type_ == macho.N_SECT;
|
||||
}
|
||||
|
||||
pub fn isUndf(sym: macho.nlist_64) bool {
|
||||
const type_ = macho.N_TYPE & sym.n_type;
|
||||
return type_ == macho.N_UNDF;
|
||||
}
|
||||
|
||||
pub fn isIndr(sym: macho.nlist_64) bool {
|
||||
const type_ = macho.N_TYPE & sym.n_type;
|
||||
return type_ == macho.N_INDR;
|
||||
}
|
||||
|
||||
pub fn isAbs(sym: macho.nlist_64) bool {
|
||||
const type_ = macho.N_TYPE & sym.n_type;
|
||||
return type_ == macho.N_ABS;
|
||||
}
|
||||
|
||||
pub fn isWeakDef(sym: macho.nlist_64) bool {
|
||||
return (sym.n_desc & macho.N_WEAK_DEF) != 0;
|
||||
}
|
||||
|
||||
pub fn isWeakRef(sym: macho.nlist_64) bool {
|
||||
return (sym.n_desc & macho.N_WEAK_REF) != 0;
|
||||
}
|
@ -5,10 +5,9 @@ const commands = @import("commands.zig");
|
||||
const log = std.log.scoped(.text_block);
|
||||
const macho = std.macho;
|
||||
const mem = std.mem;
|
||||
const reloc = @import("reloc.zig");
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const Relocation = reloc.Relocation;
|
||||
const Arch = std.Target.Cpu.Arch;
|
||||
const Zld = @import("Zld.zig");
|
||||
|
||||
allocator: *Allocator,
|
||||
@ -102,6 +101,15 @@ pub const Stab = union(enum) {
|
||||
}
|
||||
};
|
||||
|
||||
pub const Relocation = struct {
|
||||
inner: macho.relocation_info,
|
||||
where: enum {
|
||||
local,
|
||||
import,
|
||||
},
|
||||
where_index: u32,
|
||||
};
|
||||
|
||||
pub fn init(allocator: *Allocator) TextBlock {
|
||||
return .{
|
||||
.allocator = allocator,
|
||||
@ -137,18 +145,10 @@ pub fn resolveRelocs(self: *TextBlock, zld: *Zld) !void {
|
||||
|
||||
const source_addr = blk: {
|
||||
const sym = zld.locals.items[self.local_sym_index];
|
||||
break :blk sym.payload.regular.address + rel.offset;
|
||||
break :blk sym.n_value + rel.offset;
|
||||
};
|
||||
const target_addr = blk: {
|
||||
const is_via_got = switch (rel.payload) {
|
||||
.pointer_to_got => true,
|
||||
.page => |page| page.kind == .got,
|
||||
.page_off => |page_off| page_off.kind == .got,
|
||||
.load => |load| load.kind == .got,
|
||||
else => false,
|
||||
};
|
||||
|
||||
if (is_via_got) {
|
||||
if (isGotIndirection(rel, zld.target.?.cpu.arch)) {
|
||||
const dc_seg = zld.load_commands.items[zld.data_const_segment_cmd_index.?].Segment;
|
||||
const got = dc_seg.sections.items[zld.got_section_index.?];
|
||||
const got_index = rel.target.got_index orelse {
|
||||
@ -228,31 +228,18 @@ pub fn print_this(self: *const TextBlock, zld: *Zld) void {
|
||||
log.warn(" stab: {}", .{stab});
|
||||
}
|
||||
if (self.aliases.items.len > 0) {
|
||||
log.warn(" aliases:", .{});
|
||||
for (self.aliases.items) |index| {
|
||||
log.warn(" {}: {}", .{ index, zld.locals.items[index] });
|
||||
}
|
||||
log.warn(" aliases: {any}", .{self.aliases.items});
|
||||
}
|
||||
if (self.references.count() > 0) {
|
||||
log.warn(" references:", .{});
|
||||
for (self.references.keys()) |index| {
|
||||
log.warn(" {}: {}", .{ index, zld.locals.items[index] });
|
||||
}
|
||||
log.warn(" references: {any}", .{self.references.keys()});
|
||||
}
|
||||
if (self.contained) |contained| {
|
||||
log.warn(" contained symbols:", .{});
|
||||
for (contained) |sym_at_off| {
|
||||
if (sym_at_off.stab) |stab| {
|
||||
log.warn(" {}: {}, stab: {}\n", .{
|
||||
sym_at_off.offset,
|
||||
zld.locals.items[sym_at_off.local_sym_index],
|
||||
stab,
|
||||
});
|
||||
log.warn(" {}: {}, stab: {}", .{ sym_at_off.offset, sym_at_off.local_sym_index, stab });
|
||||
} else {
|
||||
log.warn(" {}: {}\n", .{
|
||||
sym_at_off.offset,
|
||||
zld.locals.items[sym_at_off.local_sym_index],
|
||||
});
|
||||
log.warn(" {}: {}", .{ sym_at_off.offset, sym_at_off.local_sym_index });
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -282,3 +269,22 @@ pub fn print(self: *const TextBlock, zld: *Zld) void {
|
||||
}
|
||||
self.print_this(zld);
|
||||
}
|
||||
|
||||
fn isGotIndirection(rel: macho.relocation_info, arch: Arch) bool {
|
||||
return switch (arch) {
|
||||
.aarch64 => switch (@intToEnum(macho.reloc_type_arm64, rel.r_type)) {
|
||||
.ARM64_RELOC_POINTER_TO_GOT,
|
||||
.ARM64_RELOC_GOT_LOAD_PAGE21,
|
||||
.ARM64_RELOC_GOT_LOAD_PAGEOFF12,
|
||||
=> true,
|
||||
else => false,
|
||||
},
|
||||
.x86_64 => switch (@intToEnum(macho.reloc_type_x86_64, rel.r_type)) {
|
||||
.X86_64_RELOC_GOT,
|
||||
.X86_64_RELOC_GOT_LOAD,
|
||||
=> true,
|
||||
else => false,
|
||||
},
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
@ -105,7 +105,6 @@ imports: std.ArrayListUnmanaged(macho.nlist_64) = .{},
|
||||
undefs: std.ArrayListUnmanaged(macho.nlist_64) = .{},
|
||||
tentatives: std.ArrayListUnmanaged(macho.nlist_64) = .{},
|
||||
symbol_resolver: std.StringArrayHashMapUnmanaged(SymbolWithLoc) = .{},
|
||||
object_mapping: std.AutoHashMapUnmanaged(u16, []u32) = .{},
|
||||
|
||||
strtab: std.ArrayListUnmanaged(u8) = .{},
|
||||
|
||||
@ -199,14 +198,6 @@ pub fn deinit(self: *Zld) void {
|
||||
}
|
||||
self.symbol_resolver.deinit(self.allocator);
|
||||
|
||||
{
|
||||
var it = self.object_mapping.valueIterator();
|
||||
while (it.next()) |value_ptr| {
|
||||
self.allocator.free(value_ptr.*);
|
||||
}
|
||||
}
|
||||
self.object_mapping.deinit(self.allocator);
|
||||
|
||||
self.strtab.deinit(self.allocator);
|
||||
|
||||
// TODO dealloc all blocks
|
||||
@ -251,33 +242,33 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg
|
||||
try self.resolveSymbols();
|
||||
|
||||
log.warn("locals", .{});
|
||||
for (self.locals.items) |sym| {
|
||||
log.warn(" | {s}: {}", .{ self.getString(sym.n_strx), sym });
|
||||
for (self.locals.items) |sym, id| {
|
||||
log.warn(" {d}: {s}, {}", .{ id, self.getString(sym.n_strx), sym });
|
||||
}
|
||||
|
||||
log.warn("globals", .{});
|
||||
for (self.globals.items) |sym| {
|
||||
log.warn(" | {s}: {}", .{ self.getString(sym.n_strx), sym });
|
||||
for (self.globals.items) |sym, id| {
|
||||
log.warn(" {d}: {s}, {}", .{ id, self.getString(sym.n_strx), sym });
|
||||
}
|
||||
|
||||
log.warn("tentatives", .{});
|
||||
for (self.tentatives.items) |sym| {
|
||||
log.warn(" | {s}: {}", .{ self.getString(sym.n_strx), sym });
|
||||
for (self.tentatives.items) |sym, id| {
|
||||
log.warn(" {d}: {s}, {}", .{ id, self.getString(sym.n_strx), sym });
|
||||
}
|
||||
|
||||
log.warn("undefines", .{});
|
||||
for (self.undefs.items) |sym| {
|
||||
log.warn(" | {s}: {}", .{ self.getString(sym.n_strx), sym });
|
||||
for (self.undefs.items) |sym, id| {
|
||||
log.warn(" {d}: {s}, {}", .{ id, self.getString(sym.n_strx), sym });
|
||||
}
|
||||
|
||||
log.warn("imports", .{});
|
||||
for (self.imports.items) |sym| {
|
||||
log.warn(" | {s}: {}", .{ self.getString(sym.n_strx), sym });
|
||||
for (self.imports.items) |sym, id| {
|
||||
log.warn(" {d}: {s}, {}", .{ id, self.getString(sym.n_strx), sym });
|
||||
}
|
||||
|
||||
log.warn("symbol resolver", .{});
|
||||
for (self.symbol_resolver.keys()) |key| {
|
||||
log.warn(" | {s} => {}", .{ key, self.symbol_resolver.get(key).? });
|
||||
log.warn(" {s} => {}", .{ key, self.symbol_resolver.get(key).? });
|
||||
}
|
||||
|
||||
log.warn("mappings", .{});
|
||||
@ -285,7 +276,7 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg
|
||||
const object_id = @intCast(u16, id);
|
||||
log.warn(" in object {s}", .{object.name.?});
|
||||
for (object.symtab.items) |sym, sym_id| {
|
||||
if (self.localSymIndex(object_id, @intCast(u32, sym_id))) |local_id| {
|
||||
if (object.symbol_mapping.get(@intCast(u32, sym_id))) |local_id| {
|
||||
log.warn(" | {d} => {d}", .{ sym_id, local_id });
|
||||
} else {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
try self.parseTextBlocks();
|
||||
|
||||
var it = self.blocks.iterator();
|
||||
while (it.next()) |entry| {
|
||||
const seg = self.load_commands.items[entry.key_ptr.seg].Segment;
|
||||
const sect = seg.sections.items[entry.key_ptr.sect];
|
||||
|
||||
log.warn("\n\n{s},{s} contents:", .{ segmentName(sect), sectionName(sect) });
|
||||
log.warn(" {}", .{sect});
|
||||
entry.value_ptr.*.print(self);
|
||||
}
|
||||
|
||||
return error.TODO;
|
||||
// try self.parseTextBlocks();
|
||||
// try self.sortSections();
|
||||
// try self.addRpaths(args.rpaths);
|
||||
// try self.addDataInCodeLC();
|
||||
@ -305,16 +307,6 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg
|
||||
// self.allocateLinkeditSegment();
|
||||
// try self.allocateTextBlocks();
|
||||
|
||||
// // var it = self.blocks.iterator();
|
||||
// // while (it.next()) |entry| {
|
||||
// // const seg = self.load_commands.items[entry.key_ptr.seg].Segment;
|
||||
// // const sect = seg.sections.items[entry.key_ptr.sect];
|
||||
|
||||
// // log.warn("\n\n{s},{s} contents:", .{ segmentName(sect), sectionName(sect) });
|
||||
// // log.warn(" {}", .{sect});
|
||||
// // entry.value_ptr.*.print(self);
|
||||
// // }
|
||||
|
||||
// try self.flush();
|
||||
}
|
||||
|
||||
@ -1414,10 +1406,6 @@ fn resolveSymbolsInObject(self: *Zld, object_id: u16) !void {
|
||||
|
||||
log.warn("resolving symbols in '{s}'", .{object.name});
|
||||
|
||||
const mapping = try self.allocator.alloc(u32, object.symtab.items.len);
|
||||
mem.set(u32, mapping, 0);
|
||||
try self.object_mapping.putNoClobber(self.allocator, object_id, mapping);
|
||||
|
||||
for (object.symtab.items) |sym, id| {
|
||||
const sym_id = @intCast(u32, id);
|
||||
const sym_name = object.getString(sym.n_strx);
|
||||
@ -1464,7 +1452,7 @@ fn resolveSymbolsInObject(self: *Zld, object_id: u16) !void {
|
||||
.n_desc = 0,
|
||||
.n_value = sym.n_value,
|
||||
});
|
||||
mapping[sym_id] = local_sym_index;
|
||||
try object.symbol_mapping.putNoClobber(self.allocator, sym_id, local_sym_index);
|
||||
|
||||
// If the symbol's scope is not local aka translation unit, then we need work out
|
||||
// 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 {
|
||||
return mem.spanZ(@ptrCast([*:0]const u8, self.strtab.items.ptr + off));
|
||||
}
|
||||
|
||||
fn localSymIndex(self: Zld, object_id: u16, orig_id: u32) ?u32 {
|
||||
const mapping = self.object_mapping.get(object_id) orelse return null;
|
||||
const local_sym_index = mapping[orig_id];
|
||||
if (local_sym_index == 0) {
|
||||
return null;
|
||||
}
|
||||
return local_sym_index;
|
||||
}
|
||||
|
||||
pub fn symbolIsStab(sym: macho.nlist_64) bool {
|
||||
return (macho.N_STAB & sym.n_type) != 0;
|
||||
}
|
||||
@ -3045,10 +3024,9 @@ pub fn symbolIsNull(sym: macho.nlist_64) bool {
|
||||
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;
|
||||
}
|
||||
|
||||
pub fn symbolIsTemp(self: Zld, sym: macho.nlist_64) bool {
|
||||
pub fn symbolIsTemp(sym: macho.nlist_64, sym_name: []const u8) bool {
|
||||
if (!symbolIsSect(sym)) return false;
|
||||
if (symbolIsExt(sym)) return false;
|
||||
const sym_name = self.getString(sym.n_strx);
|
||||
return mem.startsWith(u8, sym_name, "l") or mem.startsWith(u8, sym_name, "L");
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user