mirror of
https://github.com/ziglang/zig.git
synced 2026-02-11 03:51:08 +00:00
zld: move contents of Zld into MachO module
This commit is contained in:
parent
e0b53ad3c9
commit
f6d13e9d6f
@ -583,7 +583,6 @@ set(ZIG_STAGE2_SOURCES
|
||||
"${CMAKE_SOURCE_DIR}/src/link/MachO/Object.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"
|
||||
"${CMAKE_SOURCE_DIR}/src/link/MachO/bind.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/link/MachO/commands.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/link/Wasm.zig"
|
||||
|
||||
2602
src/link/MachO.zig
2602
src/link/MachO.zig
File diff suppressed because it is too large
Load Diff
@ -13,7 +13,7 @@ const fat = @import("fat.zig");
|
||||
const Allocator = mem.Allocator;
|
||||
const Arch = std.Target.Cpu.Arch;
|
||||
const LibStub = @import("../tapi.zig").LibStub;
|
||||
const Zld = @import("Zld.zig");
|
||||
const MachO = @import("../MachO.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 = Zld.symbolIsExt(sym) and (Zld.symbolIsSect(sym) or Zld.symbolIsIndr(sym));
|
||||
const add_to_symtab = MachO.symbolIsExt(sym) and (MachO.symbolIsSect(sym) or MachO.symbolIsIndr(sym));
|
||||
|
||||
if (!add_to_symtab) continue;
|
||||
|
||||
|
||||
@ -13,8 +13,8 @@ const sort = std.sort;
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const Arch = std.Target.Cpu.Arch;
|
||||
const MachO = @import("../MachO.zig");
|
||||
const TextBlock = @import("TextBlock.zig");
|
||||
const Zld = @import("Zld.zig");
|
||||
|
||||
usingnamespace @import("commands.zig");
|
||||
|
||||
@ -307,8 +307,8 @@ const NlistWithIndex = struct {
|
||||
}
|
||||
};
|
||||
|
||||
const start = Zld.findFirst(NlistWithIndex, symbols, 0, Predicate{ .addr = sect.addr });
|
||||
const end = Zld.findFirst(NlistWithIndex, symbols, start, Predicate{ .addr = sect.addr + sect.size });
|
||||
const start = MachO.findFirst(NlistWithIndex, symbols, 0, Predicate{ .addr = sect.addr });
|
||||
const end = MachO.findFirst(NlistWithIndex, symbols, start, Predicate{ .addr = sect.addr + sect.size });
|
||||
|
||||
return symbols[start..end];
|
||||
}
|
||||
@ -323,8 +323,8 @@ fn filterDice(dices: []macho.data_in_code_entry, start_addr: u64, end_addr: u64)
|
||||
}
|
||||
};
|
||||
|
||||
const start = Zld.findFirst(macho.data_in_code_entry, dices, 0, Predicate{ .addr = start_addr });
|
||||
const end = Zld.findFirst(macho.data_in_code_entry, dices, start, Predicate{ .addr = end_addr });
|
||||
const start = MachO.findFirst(macho.data_in_code_entry, dices, 0, Predicate{ .addr = start_addr });
|
||||
const end = MachO.findFirst(macho.data_in_code_entry, dices, start, Predicate{ .addr = end_addr });
|
||||
|
||||
return dices[start..end];
|
||||
}
|
||||
@ -335,10 +335,10 @@ const TextBlockParser = struct {
|
||||
code: []u8,
|
||||
relocs: []macho.relocation_info,
|
||||
object: *Object,
|
||||
zld: *Zld,
|
||||
macho_file: *MachO,
|
||||
nlists: []NlistWithIndex,
|
||||
index: u32 = 0,
|
||||
match: Zld.MatchingSection,
|
||||
match: MachO.MatchingSection,
|
||||
|
||||
fn peek(self: *TextBlockParser) ?NlistWithIndex {
|
||||
return if (self.index + 1 < self.nlists.len) self.nlists[self.index + 1] else null;
|
||||
@ -349,10 +349,10 @@ const TextBlockParser = struct {
|
||||
};
|
||||
|
||||
fn lessThanBySeniority(context: SeniorityContext, lhs: NlistWithIndex, rhs: NlistWithIndex) bool {
|
||||
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);
|
||||
if (!MachO.symbolIsExt(rhs.nlist)) {
|
||||
return MachO.symbolIsTemp(lhs.nlist, context.object.getString(lhs.nlist.n_strx));
|
||||
} else if (MachO.symbolIsPext(rhs.nlist) or MachO.symbolIsWeakDef(rhs.nlist)) {
|
||||
return !MachO.symbolIsExt(lhs.nlist);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
@ -383,7 +383,7 @@ const TextBlockParser = struct {
|
||||
const sym = self.object.symbols.items[nlist_with_index.index];
|
||||
if (sym.payload != .regular) {
|
||||
log.err("expected a regular symbol, found {s}", .{sym.payload});
|
||||
log.err(" when remapping {s}", .{self.zld.getString(sym.strx)});
|
||||
log.err(" when remapping {s}", .{self.macho_file.getString(sym.strx)});
|
||||
return error.SymbolIsNotRegular;
|
||||
}
|
||||
assert(sym.payload.regular.local_sym_index != 0); // This means the symbol has not been properly resolved.
|
||||
@ -401,7 +401,7 @@ const TextBlockParser = struct {
|
||||
}
|
||||
|
||||
const senior_nlist = aliases.pop();
|
||||
const senior_sym = self.zld.locals.items[senior_nlist.index];
|
||||
const senior_sym = self.macho_file.locals.items[senior_nlist.index];
|
||||
assert(senior_sym.payload == .regular);
|
||||
senior_sym.payload.regular.segment_id = self.match.seg;
|
||||
senior_sym.payload.regular.section_id = self.match.sect;
|
||||
@ -429,7 +429,7 @@ const TextBlockParser = struct {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (self.zld.globals.contains(self.zld.getString(senior_sym.strx))) break :blk .global;
|
||||
if (self.macho_file.globals.contains(self.macho_file.getString(senior_sym.strx))) break :blk .global;
|
||||
break :blk .static;
|
||||
} else null;
|
||||
|
||||
@ -448,19 +448,19 @@ const TextBlockParser = struct {
|
||||
for (aliases.items) |alias| {
|
||||
block.aliases.appendAssumeCapacity(alias.index);
|
||||
|
||||
const sym = self.zld.locals.items[alias.index];
|
||||
const sym = self.macho_file.locals.items[alias.index];
|
||||
const reg = &sym.payload.regular;
|
||||
reg.segment_id = self.match.seg;
|
||||
reg.section_id = self.match.sect;
|
||||
}
|
||||
}
|
||||
|
||||
try block.parseRelocsFromObject(relocs, object, .{
|
||||
try block.parseRelocsFromObject(self.allocator, relocs, object, .{
|
||||
.base_addr = start_addr,
|
||||
.zld = self.zld,
|
||||
.macho_file = self.macho_file,
|
||||
});
|
||||
|
||||
if (self.zld.has_dices) {
|
||||
if (self.macho_file.has_dices) {
|
||||
const dices = filterDice(
|
||||
self.object.data_in_code_entries.items,
|
||||
senior_nlist.nlist.n_value,
|
||||
@ -483,7 +483,7 @@ const TextBlockParser = struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
|
||||
pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void {
|
||||
const seg = self.load_commands.items[self.segment_cmd_index.?].Segment;
|
||||
|
||||
log.debug("analysing {s}", .{self.name.?});
|
||||
@ -513,7 +513,7 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
|
||||
});
|
||||
|
||||
// Get matching segment/section in the final artifact.
|
||||
const match = (try zld.getMatchingSection(sect)) orelse {
|
||||
const match = (try macho_file.getMatchingSection(sect)) orelse {
|
||||
log.debug("unhandled section", .{});
|
||||
continue;
|
||||
};
|
||||
@ -538,7 +538,7 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
|
||||
// duplicates at all? Need some benchmarks!
|
||||
// const is_splittable = false;
|
||||
|
||||
zld.has_dices = blk: {
|
||||
macho_file.has_dices = blk: {
|
||||
if (self.text_section_index) |index| {
|
||||
if (index != id) break :blk false;
|
||||
if (self.data_in_code_entries.items.len == 0) break :blk false;
|
||||
@ -546,7 +546,7 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
|
||||
}
|
||||
break :blk false;
|
||||
};
|
||||
zld.has_stabs = zld.has_stabs or self.debug_info != null;
|
||||
macho_file.has_stabs = macho_file.has_stabs or self.debug_info != null;
|
||||
|
||||
{
|
||||
// next: {
|
||||
@ -711,11 +711,11 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
|
||||
defer self.allocator.free(sym_name);
|
||||
|
||||
const block_local_sym_index = self.sections_as_symbols.get(sect_id) orelse blk: {
|
||||
const block_local_sym_index = @intCast(u32, zld.locals.items.len);
|
||||
try zld.locals.append(zld.allocator, .{
|
||||
.n_strx = try zld.makeString(sym_name),
|
||||
const block_local_sym_index = @intCast(u32, macho_file.locals.items.len);
|
||||
try macho_file.locals.append(macho_file.base.allocator, .{
|
||||
.n_strx = try macho_file.makeString(sym_name),
|
||||
.n_type = macho.N_SECT,
|
||||
.n_sect = zld.sectionId(match),
|
||||
.n_sect = macho_file.sectionId(match),
|
||||
.n_desc = 0,
|
||||
.n_value = sect.addr,
|
||||
});
|
||||
@ -726,20 +726,20 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
|
||||
const block = try self.allocator.create(TextBlock);
|
||||
errdefer self.allocator.destroy(block);
|
||||
|
||||
block.* = TextBlock.init(self.allocator);
|
||||
block.* = TextBlock.empty;
|
||||
block.local_sym_index = block_local_sym_index;
|
||||
block.code = try self.allocator.dupe(u8, code);
|
||||
block.size = sect.size;
|
||||
block.alignment = sect.@"align";
|
||||
|
||||
try block.parseRelocsFromObject(relocs, self, .{
|
||||
try block.parseRelocsFromObject(self.allocator, relocs, self, .{
|
||||
.base_addr = 0,
|
||||
.zld = zld,
|
||||
.macho_file = macho_file,
|
||||
});
|
||||
|
||||
if (zld.has_dices) {
|
||||
if (macho_file.has_dices) {
|
||||
const dices = filterDice(self.data_in_code_entries.items, sect.addr, sect.addr + sect.size);
|
||||
try block.dices.ensureTotalCapacity(dices.len);
|
||||
try block.dices.ensureTotalCapacity(self.allocator, dices.len);
|
||||
|
||||
for (dices) |dice| {
|
||||
block.dices.appendAssumeCapacity(.{
|
||||
@ -755,15 +755,13 @@ 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.
|
||||
var contained = std.ArrayList(TextBlock.SymbolAtOffset).init(self.allocator);
|
||||
defer contained.deinit();
|
||||
try contained.ensureTotalCapacity(filtered_nlists.len);
|
||||
try block.contained.ensureTotalCapacity(self.allocator, filtered_nlists.len);
|
||||
|
||||
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);
|
||||
const local = &macho_file.locals.items[local_sym_index];
|
||||
local.n_sect = macho_file.sectionId(match);
|
||||
|
||||
const stab: ?TextBlock.Stab = if (self.debug_info) |di| blk: {
|
||||
// TODO there has to be a better to handle this.
|
||||
@ -781,19 +779,17 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
|
||||
break :blk .static;
|
||||
} else null;
|
||||
|
||||
contained.appendAssumeCapacity(.{
|
||||
block.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?
|
||||
const tseg = &zld.load_commands.items[match.seg].Segment;
|
||||
const tseg = &macho_file.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);
|
||||
@ -801,12 +797,12 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
|
||||
tsect.size = new_size;
|
||||
tsect.@"align" = new_alignment;
|
||||
|
||||
if (zld.blocks.getPtr(match)) |last| {
|
||||
if (macho_file.blocks.getPtr(match)) |last| {
|
||||
last.*.next = block;
|
||||
block.prev = last.*;
|
||||
last.* = block;
|
||||
} else {
|
||||
try zld.blocks.putNoClobber(zld.allocator, match, block);
|
||||
try macho_file.blocks.putNoClobber(self.allocator, match, block);
|
||||
}
|
||||
|
||||
try self.text_blocks.append(self.allocator, block);
|
||||
@ -814,7 +810,7 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn symbolFromReloc(self: *Object, zld: *Zld, rel: macho.relocation_info) !*Symbol {
|
||||
pub fn symbolFromReloc(self: *Object, macho_file: *MachO, rel: macho.relocation_info) !*Symbol {
|
||||
const symbol = blk: {
|
||||
if (rel.r_extern == 1) {
|
||||
break :blk self.symbols.items[rel.r_symbolnum];
|
||||
@ -832,9 +828,9 @@ pub fn symbolFromReloc(self: *Object, zld: *Zld, rel: macho.relocation_info) !*S
|
||||
sectionName(sect),
|
||||
});
|
||||
defer self.allocator.free(name);
|
||||
const symbol = try zld.allocator.create(Symbol);
|
||||
const symbol = try macho_file.allocator.create(Symbol);
|
||||
symbol.* = .{
|
||||
.strx = try zld.makeString(name),
|
||||
.strx = try macho_file.makeString(name),
|
||||
.payload = .{
|
||||
.regular = .{
|
||||
.linkage = .translation_unit,
|
||||
|
||||
@ -12,24 +12,64 @@ const meta = std.meta;
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const Arch = std.Target.Cpu.Arch;
|
||||
const MachO = @import("../MachO.zig");
|
||||
const Object = @import("Object.zig");
|
||||
const Zld = @import("Zld.zig");
|
||||
|
||||
allocator: *Allocator,
|
||||
/// Each decl always gets a local symbol with the fully qualified name.
|
||||
/// The vaddr and size are found here directly.
|
||||
/// The file offset is found by computing the vaddr offset from the section vaddr
|
||||
/// the symbol references, and adding that to the file offset of the section.
|
||||
/// If this field is 0, it means the codegen size = 0 and there is no symbol or
|
||||
/// offset table entry.
|
||||
local_sym_index: u32,
|
||||
stab: ?Stab = null,
|
||||
aliases: std.ArrayList(u32),
|
||||
references: std.AutoArrayHashMap(u32, void),
|
||||
contained: ?[]SymbolAtOffset = null,
|
||||
|
||||
/// List of symbol aliases pointing to the same block via different nlists
|
||||
aliases: std.ArrayListUnmanaged(u32) = .{},
|
||||
|
||||
/// List of symbols contained within this block
|
||||
contained: std.ArrayListUnmanaged(SymbolAtOffset) = .{},
|
||||
|
||||
/// Code (may be non-relocated) this block represents
|
||||
code: []u8,
|
||||
relocs: std.ArrayList(Relocation),
|
||||
|
||||
/// Size and alignment of this text block
|
||||
/// Unlike in Elf, we need to store the size of this symbol as part of
|
||||
/// the TextBlock since macho.nlist_64 lacks this information.
|
||||
size: u64,
|
||||
alignment: u32,
|
||||
rebases: std.ArrayList(u64),
|
||||
bindings: std.ArrayList(SymbolAtOffset),
|
||||
dices: std.ArrayList(macho.data_in_code_entry),
|
||||
next: ?*TextBlock = null,
|
||||
prev: ?*TextBlock = null,
|
||||
|
||||
relocs: std.ArrayListUnmanaged(Relocation) = .{},
|
||||
|
||||
/// List of offsets contained within this block that need rebasing by the dynamic
|
||||
/// loader in presence of ASLR
|
||||
rebases: std.ArrayListUnmanaged(u64) = .{},
|
||||
|
||||
/// List of offsets contained within this block that will be dynamically bound
|
||||
/// by the dynamic loader and contain pointers to resolved (at load time) extern
|
||||
/// symbols (aka proxies aka imports)
|
||||
bindings: std.ArrayListUnmanaged(SymbolAtOffset) = .{},
|
||||
|
||||
/// List of data-in-code entries. This is currently specific to x86_64 only.
|
||||
dices: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{},
|
||||
|
||||
/// Stab entry for this block. This is currently specific to a binary created
|
||||
/// by linking object files in a traditional sense - in incremental sense, we
|
||||
/// bypass stabs altogether to produce dSYM bundle directly with fully relocated
|
||||
/// DWARF sections.
|
||||
stab: ?Stab = null,
|
||||
|
||||
/// Points to the previous and next neighbours
|
||||
next: ?*TextBlock,
|
||||
prev: ?*TextBlock,
|
||||
|
||||
/// Previous/next linked list pointers.
|
||||
/// This is the linked list node for this Decl's corresponding .debug_info tag.
|
||||
dbg_info_prev: ?*TextBlock,
|
||||
dbg_info_next: ?*TextBlock,
|
||||
/// Offset into .debug_info pointing to the tag for this Decl.
|
||||
dbg_info_off: u32,
|
||||
/// Size of the .debug_info tag for this Decl, not including padding.
|
||||
dbg_info_len: u32,
|
||||
|
||||
pub const SymbolAtOffset = struct {
|
||||
local_sym_index: u32,
|
||||
@ -42,11 +82,11 @@ pub const Stab = union(enum) {
|
||||
static,
|
||||
global,
|
||||
|
||||
pub fn asNlists(stab: Stab, local_sym_index: u32, zld: *Zld) ![]macho.nlist_64 {
|
||||
var nlists = std.ArrayList(macho.nlist_64).init(zld.allocator);
|
||||
pub fn asNlists(stab: Stab, local_sym_index: u32, macho_file: anytype) ![]macho.nlist_64 {
|
||||
var nlists = std.ArrayList(macho.nlist_64).init(macho_file.base.allocator);
|
||||
defer nlists.deinit();
|
||||
|
||||
const sym = zld.locals.items[local_sym_index];
|
||||
const sym = macho_file.locals.items[local_sym_index];
|
||||
switch (stab) {
|
||||
.function => |size| {
|
||||
try nlists.ensureUnusedCapacity(4);
|
||||
@ -130,7 +170,7 @@ pub const Relocation = struct {
|
||||
offset: u32,
|
||||
source_addr: u64,
|
||||
target_addr: u64,
|
||||
zld: *Zld,
|
||||
macho_file: *MachO,
|
||||
};
|
||||
|
||||
pub const Unsigned = struct {
|
||||
@ -148,7 +188,7 @@ pub const Relocation = struct {
|
||||
pub fn resolve(self: Unsigned, args: ResolveArgs) !void {
|
||||
const result = blk: {
|
||||
if (self.subtractor) |subtractor| {
|
||||
const sym = args.zld.locals.items[subtractor];
|
||||
const sym = args.macho_file.locals.items[subtractor];
|
||||
break :blk @intCast(i64, args.target_addr) - @intCast(i64, sym.n_value) + self.addend;
|
||||
} else {
|
||||
break :blk @intCast(i64, args.target_addr) + self.addend;
|
||||
@ -500,38 +540,59 @@ pub const Relocation = struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub fn init(allocator: *Allocator) TextBlock {
|
||||
return .{
|
||||
.allocator = allocator,
|
||||
.local_sym_index = undefined,
|
||||
.aliases = std.ArrayList(u32).init(allocator),
|
||||
.references = std.AutoArrayHashMap(u32, void).init(allocator),
|
||||
.code = undefined,
|
||||
.relocs = std.ArrayList(Relocation).init(allocator),
|
||||
.size = undefined,
|
||||
.alignment = undefined,
|
||||
.rebases = std.ArrayList(u64).init(allocator),
|
||||
.bindings = std.ArrayList(SymbolAtOffset).init(allocator),
|
||||
.dices = std.ArrayList(macho.data_in_code_entry).init(allocator),
|
||||
};
|
||||
pub const empty = TextBlock{
|
||||
.local_sym_index = 0,
|
||||
.code = undefined,
|
||||
.size = 0,
|
||||
.alignment = 0,
|
||||
.prev = null,
|
||||
.next = null,
|
||||
.dbg_info_prev = null,
|
||||
.dbg_info_next = null,
|
||||
.dbg_info_off = undefined,
|
||||
.dbg_info_len = undefined,
|
||||
};
|
||||
|
||||
pub fn deinit(self: *TextBlock, allocator: *Allocator) void {
|
||||
self.dices.deinit(allocator);
|
||||
self.bindings.deinit(allocator);
|
||||
self.rebases.deinit(allocator);
|
||||
self.relocs.deinit(allocator);
|
||||
self.allocator.free(self.code);
|
||||
self.contained.deinit(allocator);
|
||||
self.aliases.deinit(allocator);
|
||||
}
|
||||
|
||||
pub fn deinit(self: *TextBlock) void {
|
||||
self.aliases.deinit();
|
||||
self.references.deinit();
|
||||
if (self.contained) |contained| {
|
||||
self.allocator.free(contained);
|
||||
/// Returns how much room there is to grow in virtual address space.
|
||||
/// File offset relocation happens transparently, so it is not included in
|
||||
/// this calculation.
|
||||
pub fn capacity(self: TextBlock, macho_file: MachO) u64 {
|
||||
const self_sym = macho_file.locals.items[self.local_sym_index];
|
||||
if (self.next) |next| {
|
||||
const next_sym = macho_file.locals.items[next.local_sym_index];
|
||||
return next_sym.n_value - self_sym.n_value;
|
||||
} else {
|
||||
// We are the last block.
|
||||
// The capacity is limited only by virtual address space.
|
||||
return std.math.maxInt(u64) - self_sym.n_value;
|
||||
}
|
||||
self.allocator.free(self.code);
|
||||
self.relocs.deinit();
|
||||
self.rebases.deinit();
|
||||
self.bindings.deinit();
|
||||
self.dices.deinit();
|
||||
}
|
||||
|
||||
pub fn freeListEligible(self: TextBlock, macho_file: MachO) bool {
|
||||
// No need to keep a free list node for the last block.
|
||||
const next = self.next orelse return false;
|
||||
const self_sym = macho_file.locals.items[self.local_sym_index];
|
||||
const next_sym = macho_file.locals.items[next.local_sym_index];
|
||||
const cap = next_sym.n_value - self_sym.n_value;
|
||||
const ideal_cap = MachO.padToIdeal(self.size);
|
||||
if (cap <= ideal_cap) return false;
|
||||
const surplus = cap - ideal_cap;
|
||||
return surplus >= MachO.min_text_capacity;
|
||||
}
|
||||
|
||||
const RelocContext = struct {
|
||||
base_addr: u64 = 0,
|
||||
zld: *Zld,
|
||||
macho_file: *MachO,
|
||||
};
|
||||
|
||||
fn initRelocFromObject(rel: macho.relocation_info, object: *Object, ctx: RelocContext) !Relocation {
|
||||
@ -548,19 +609,19 @@ fn initRelocFromObject(rel: macho.relocation_info, object: *Object, ctx: RelocCo
|
||||
const local_sym_index = object.sections_as_symbols.get(sect_id) orelse blk: {
|
||||
const seg = object.load_commands.items[object.segment_cmd_index.?].Segment;
|
||||
const sect = seg.sections.items[sect_id];
|
||||
const match = (try ctx.zld.getMatchingSection(sect)) orelse unreachable;
|
||||
const local_sym_index = @intCast(u32, ctx.zld.locals.items.len);
|
||||
const sym_name = try std.fmt.allocPrint(ctx.zld.allocator, "l_{s}_{s}_{s}", .{
|
||||
const match = (try ctx.macho_file.getMatchingSection(sect)) orelse unreachable;
|
||||
const local_sym_index = @intCast(u32, ctx.macho_file.locals.items.len);
|
||||
const sym_name = try std.fmt.allocPrint(ctx.macho_file.base.allocator, "l_{s}_{s}_{s}", .{
|
||||
object.name.?,
|
||||
commands.segmentName(sect),
|
||||
commands.sectionName(sect),
|
||||
});
|
||||
defer ctx.zld.allocator.free(sym_name);
|
||||
defer ctx.macho_file.base.allocator.free(sym_name);
|
||||
|
||||
try ctx.zld.locals.append(ctx.zld.allocator, .{
|
||||
.n_strx = try ctx.zld.makeString(sym_name),
|
||||
try ctx.macho_file.locals.append(ctx.macho_file.base.allocator, .{
|
||||
.n_strx = try ctx.macho_file.makeString(sym_name),
|
||||
.n_type = macho.N_SECT,
|
||||
.n_sect = ctx.zld.sectionId(match),
|
||||
.n_sect = ctx.macho_file.sectionId(match),
|
||||
.n_desc = 0,
|
||||
.n_value = sect.addr,
|
||||
});
|
||||
@ -574,12 +635,12 @@ fn initRelocFromObject(rel: macho.relocation_info, object: *Object, ctx: RelocCo
|
||||
const sym = object.symtab.items[rel.r_symbolnum];
|
||||
const sym_name = object.getString(sym.n_strx);
|
||||
|
||||
if (Zld.symbolIsSect(sym) and !Zld.symbolIsExt(sym)) {
|
||||
if (MachO.symbolIsSect(sym) and !MachO.symbolIsExt(sym)) {
|
||||
const where_index = object.symbol_mapping.get(rel.r_symbolnum) orelse unreachable;
|
||||
parsed_rel.where = .local;
|
||||
parsed_rel.where_index = where_index;
|
||||
} else {
|
||||
const resolv = ctx.zld.symbol_resolver.get(sym_name) orelse unreachable;
|
||||
const resolv = ctx.macho_file.symbol_resolver.get(sym_name) orelse unreachable;
|
||||
switch (resolv.where) {
|
||||
.global => {
|
||||
parsed_rel.where = .local;
|
||||
@ -599,6 +660,7 @@ fn initRelocFromObject(rel: macho.relocation_info, object: *Object, ctx: RelocCo
|
||||
|
||||
pub fn parseRelocsFromObject(
|
||||
self: *TextBlock,
|
||||
allocator: *Allocator,
|
||||
relocs: []macho.relocation_info,
|
||||
object: *Object,
|
||||
ctx: RelocContext,
|
||||
@ -638,11 +700,11 @@ pub fn parseRelocsFromObject(
|
||||
const sym = object.symtab.items[rel.r_symbolnum];
|
||||
const sym_name = object.getString(sym.n_strx);
|
||||
|
||||
if (Zld.symbolIsSect(sym) and !Zld.symbolIsExt(sym)) {
|
||||
if (MachO.symbolIsSect(sym) and !MachO.symbolIsExt(sym)) {
|
||||
const where_index = object.symbol_mapping.get(rel.r_symbolnum) orelse unreachable;
|
||||
subtractor = where_index;
|
||||
} else {
|
||||
const resolv = ctx.zld.symbol_resolver.get(sym_name) orelse unreachable;
|
||||
const resolv = ctx.macho_file.symbol_resolver.get(sym_name) orelse unreachable;
|
||||
assert(resolv.where == .global);
|
||||
subtractor = resolv.local_sym_index;
|
||||
}
|
||||
@ -732,11 +794,7 @@ pub fn parseRelocsFromObject(
|
||||
else => unreachable,
|
||||
}
|
||||
|
||||
try self.relocs.append(parsed_rel);
|
||||
|
||||
if (parsed_rel.where == .local) {
|
||||
try self.references.put(parsed_rel.where_index, {});
|
||||
}
|
||||
try self.relocs.append(allocator, parsed_rel);
|
||||
|
||||
const is_via_got = switch (parsed_rel.payload) {
|
||||
.pointer_to_got => true,
|
||||
@ -747,28 +805,30 @@ pub fn parseRelocsFromObject(
|
||||
};
|
||||
|
||||
if (is_via_got) blk: {
|
||||
const key = Zld.GotIndirectionKey{
|
||||
const key = MachO.GotIndirectionKey{
|
||||
.where = switch (parsed_rel.where) {
|
||||
.local => .local,
|
||||
.import => .import,
|
||||
},
|
||||
.where_index = parsed_rel.where_index,
|
||||
};
|
||||
if (ctx.zld.got_entries.contains(key)) break :blk;
|
||||
if (ctx.macho_file.got_entries_map.contains(key)) break :blk;
|
||||
|
||||
try ctx.zld.got_entries.putNoClobber(ctx.zld.allocator, key, {});
|
||||
const got_index = @intCast(u32, ctx.macho_file.got_entries.items.len);
|
||||
try ctx.macho_file.got_entries.append(ctx.macho_file.base.allocator, key);
|
||||
try ctx.macho_file.got_entries_map.putNoClobber(ctx.macho_file.base.allocator, key, got_index);
|
||||
} else if (parsed_rel.payload == .unsigned) {
|
||||
switch (parsed_rel.where) {
|
||||
.import => {
|
||||
try self.bindings.append(.{
|
||||
try self.bindings.append(allocator, .{
|
||||
.local_sym_index = parsed_rel.where_index,
|
||||
.offset = parsed_rel.offset,
|
||||
});
|
||||
},
|
||||
.local => {
|
||||
const source_sym = ctx.zld.locals.items[self.local_sym_index];
|
||||
const match = ctx.zld.unpackSectionId(source_sym.n_sect);
|
||||
const seg = ctx.zld.load_commands.items[match.seg].Segment;
|
||||
const source_sym = ctx.macho_file.locals.items[self.local_sym_index];
|
||||
const match = ctx.macho_file.unpackSectionId(source_sym.n_sect);
|
||||
const seg = ctx.macho_file.load_commands.items[match.seg].Segment;
|
||||
const sect = seg.sections.items[match.sect];
|
||||
const sect_type = commands.sectionType(sect);
|
||||
|
||||
@ -778,12 +838,12 @@ pub fn parseRelocsFromObject(
|
||||
// TODO actually, a check similar to what dyld is doing, that is, verifying
|
||||
// that the segment is writable should be enough here.
|
||||
const is_right_segment = blk: {
|
||||
if (ctx.zld.data_segment_cmd_index) |idx| {
|
||||
if (ctx.macho_file.data_segment_cmd_index) |idx| {
|
||||
if (match.seg == idx) {
|
||||
break :blk true;
|
||||
}
|
||||
}
|
||||
if (ctx.zld.data_const_segment_cmd_index) |idx| {
|
||||
if (ctx.macho_file.data_const_segment_cmd_index) |idx| {
|
||||
if (match.seg == idx) {
|
||||
break :blk true;
|
||||
}
|
||||
@ -804,15 +864,17 @@ pub fn parseRelocsFromObject(
|
||||
};
|
||||
|
||||
if (should_rebase) {
|
||||
try self.rebases.append(parsed_rel.offset);
|
||||
try self.rebases.append(allocator, parsed_rel.offset);
|
||||
}
|
||||
},
|
||||
}
|
||||
} else if (parsed_rel.payload == .branch) blk: {
|
||||
if (parsed_rel.where != .import) break :blk;
|
||||
if (ctx.zld.stubs.contains(parsed_rel.where_index)) break :blk;
|
||||
if (ctx.macho_file.stubs_map.contains(parsed_rel.where_index)) break :blk;
|
||||
|
||||
try ctx.zld.stubs.putNoClobber(ctx.zld.allocator, parsed_rel.where_index, {});
|
||||
const stubs_index = @intCast(u32, ctx.macho_file.stubs.items.len);
|
||||
try ctx.macho_file.stubs.append(ctx.macho_file.base.allocator, parsed_rel.where_index);
|
||||
try ctx.macho_file.stubs_map.putNoClobber(ctx.macho_file.base.allocator, parsed_rel.where_index, stubs_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -852,7 +914,7 @@ fn parseUnsigned(
|
||||
|
||||
if (rel.r_extern == 0) {
|
||||
assert(out.where == .local);
|
||||
const target_sym = ctx.zld.locals.items[out.where_index];
|
||||
const target_sym = ctx.macho_file.locals.items[out.where_index];
|
||||
addend -= @intCast(i64, target_sym.n_value);
|
||||
}
|
||||
|
||||
@ -872,7 +934,7 @@ fn parseBranch(self: TextBlock, rel: macho.relocation_info, out: *Relocation, ct
|
||||
|
||||
out.payload = .{
|
||||
.branch = .{
|
||||
.arch = ctx.zld.target.?.cpu.arch,
|
||||
.arch = ctx.macho_file.base.options.target.cpu.arch,
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -948,10 +1010,10 @@ fn parseSigned(self: TextBlock, rel: macho.relocation_info, out: *Relocation, ct
|
||||
var addend: i64 = mem.readIntLittle(i32, self.code[out.offset..][0..4]) + correction;
|
||||
|
||||
if (rel.r_extern == 0) {
|
||||
const source_sym = ctx.zld.locals.items[self.local_sym_index];
|
||||
const source_sym = ctx.macho_file.locals.items[self.local_sym_index];
|
||||
const target_sym = switch (out.where) {
|
||||
.local => ctx.zld.locals.items[out.where_index],
|
||||
.import => ctx.zld.imports.items[out.where_index],
|
||||
.local => ctx.macho_file.locals.items[out.where_index],
|
||||
.import => ctx.macho_file.imports.items[out.where_index],
|
||||
};
|
||||
addend = @intCast(i64, source_sym.n_value + out.offset + 4) + addend - @intCast(i64, target_sym.n_value);
|
||||
}
|
||||
@ -986,12 +1048,12 @@ fn parseLoad(self: TextBlock, rel: macho.relocation_info, out: *Relocation) void
|
||||
};
|
||||
}
|
||||
|
||||
pub fn resolveRelocs(self: *TextBlock, zld: *Zld) !void {
|
||||
pub fn resolveRelocs(self: *TextBlock, macho_file: *MachO) !void {
|
||||
for (self.relocs.items) |rel| {
|
||||
log.debug("relocating {}", .{rel});
|
||||
|
||||
const source_addr = blk: {
|
||||
const sym = zld.locals.items[self.local_sym_index];
|
||||
const sym = macho_file.locals.items[self.local_sym_index];
|
||||
break :blk sym.n_value + rel.offset;
|
||||
};
|
||||
const target_addr = blk: {
|
||||
@ -1004,9 +1066,9 @@ pub fn resolveRelocs(self: *TextBlock, zld: *Zld) !void {
|
||||
};
|
||||
|
||||
if (is_via_got) {
|
||||
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 = zld.got_entries.getIndex(.{
|
||||
const dc_seg = macho_file.load_commands.items[macho_file.data_const_segment_cmd_index.?].Segment;
|
||||
const got = dc_seg.sections.items[macho_file.got_section_index.?];
|
||||
const got_index = macho_file.got_entries_map.get(.{
|
||||
.where = switch (rel.where) {
|
||||
.local => .local,
|
||||
.import => .import,
|
||||
@ -1014,10 +1076,10 @@ pub fn resolveRelocs(self: *TextBlock, zld: *Zld) !void {
|
||||
.where_index = rel.where_index,
|
||||
}) orelse {
|
||||
const sym = switch (rel.where) {
|
||||
.local => zld.locals.items[rel.where_index],
|
||||
.import => zld.imports.items[rel.where_index],
|
||||
.local => macho_file.locals.items[rel.where_index],
|
||||
.import => macho_file.imports.items[rel.where_index],
|
||||
};
|
||||
log.err("expected GOT entry for symbol '{s}'", .{zld.getString(sym.n_strx)});
|
||||
log.err("expected GOT entry for symbol '{s}'", .{macho_file.getString(sym.n_strx)});
|
||||
log.err(" this is an internal linker error", .{});
|
||||
return error.FailedToResolveRelocationTarget;
|
||||
};
|
||||
@ -1026,11 +1088,11 @@ pub fn resolveRelocs(self: *TextBlock, zld: *Zld) !void {
|
||||
|
||||
switch (rel.where) {
|
||||
.local => {
|
||||
const sym = zld.locals.items[rel.where_index];
|
||||
const sym = macho_file.locals.items[rel.where_index];
|
||||
const is_tlv = is_tlv: {
|
||||
const source_sym = zld.locals.items[self.local_sym_index];
|
||||
const match = zld.unpackSectionId(source_sym.n_sect);
|
||||
const seg = zld.load_commands.items[match.seg].Segment;
|
||||
const source_sym = macho_file.locals.items[self.local_sym_index];
|
||||
const match = macho_file.unpackSectionId(source_sym.n_sect);
|
||||
const seg = macho_file.load_commands.items[match.seg].Segment;
|
||||
const sect = seg.sections.items[match.sect];
|
||||
break :is_tlv commands.sectionType(sect) == macho.S_THREAD_LOCAL_VARIABLES;
|
||||
};
|
||||
@ -1040,11 +1102,11 @@ pub fn resolveRelocs(self: *TextBlock, zld: *Zld) !void {
|
||||
// defined TLV template init section in the following order:
|
||||
// * wrt to __thread_data if defined, then
|
||||
// * wrt to __thread_bss
|
||||
const seg = zld.load_commands.items[zld.data_segment_cmd_index.?].Segment;
|
||||
const seg = macho_file.load_commands.items[macho_file.data_segment_cmd_index.?].Segment;
|
||||
const base_address = inner: {
|
||||
if (zld.tlv_data_section_index) |i| {
|
||||
if (macho_file.tlv_data_section_index) |i| {
|
||||
break :inner seg.sections.items[i].addr;
|
||||
} else if (zld.tlv_bss_section_index) |i| {
|
||||
} else if (macho_file.tlv_bss_section_index) |i| {
|
||||
break :inner seg.sections.items[i].addr;
|
||||
} else {
|
||||
log.err("threadlocal variables present but no initializer sections found", .{});
|
||||
@ -1059,12 +1121,12 @@ pub fn resolveRelocs(self: *TextBlock, zld: *Zld) !void {
|
||||
break :blk sym.n_value;
|
||||
},
|
||||
.import => {
|
||||
const stubs_index = zld.stubs.getIndex(rel.where_index) orelse {
|
||||
const stubs_index = macho_file.stubs_map.get(rel.where_index) orelse {
|
||||
// TODO verify in TextBlock that the symbol is indeed dynamically bound.
|
||||
break :blk 0; // Dynamically bound by dyld.
|
||||
};
|
||||
const segment = zld.load_commands.items[zld.text_segment_cmd_index.?].Segment;
|
||||
const stubs = segment.sections.items[zld.stubs_section_index.?];
|
||||
const segment = macho_file.load_commands.items[macho_file.text_segment_cmd_index.?].Segment;
|
||||
const stubs = segment.sections.items[macho_file.stubs_section_index.?];
|
||||
break :blk stubs.addr + stubs_index * stubs.reserved2;
|
||||
},
|
||||
}
|
||||
@ -1078,14 +1140,14 @@ pub fn resolveRelocs(self: *TextBlock, zld: *Zld) !void {
|
||||
.offset = rel.offset,
|
||||
.source_addr = source_addr,
|
||||
.target_addr = target_addr,
|
||||
.zld = zld,
|
||||
.macho_file = macho_file,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print_this(self: *const TextBlock, zld: *Zld) void {
|
||||
pub fn print_this(self: *const TextBlock, macho_file: MachO) void {
|
||||
log.warn("TextBlock", .{});
|
||||
log.warn(" {}: {}", .{ self.local_sym_index, zld.locals.items[self.local_sym_index] });
|
||||
log.warn(" {}: {}", .{ self.local_sym_index, macho_file.locals.items[self.local_sym_index] });
|
||||
if (self.stab) |stab| {
|
||||
log.warn(" stab: {}", .{stab});
|
||||
}
|
||||
@ -1125,11 +1187,11 @@ pub fn print_this(self: *const TextBlock, zld: *Zld) void {
|
||||
log.warn(" align = {}", .{self.alignment});
|
||||
}
|
||||
|
||||
pub fn print(self: *const TextBlock, zld: *Zld) void {
|
||||
pub fn print(self: *const TextBlock, macho_file: MachO) void {
|
||||
if (self.prev) |prev| {
|
||||
prev.print(zld);
|
||||
prev.print(macho_file);
|
||||
}
|
||||
self.print_this(zld);
|
||||
self.print_this(macho_file);
|
||||
}
|
||||
|
||||
const RelocIterator = struct {
|
||||
@ -1159,8 +1221,8 @@ fn filterRelocs(relocs: []macho.relocation_info, start_addr: u64, end_addr: u64)
|
||||
}
|
||||
};
|
||||
|
||||
const start = Zld.findFirst(macho.relocation_info, relocs, 0, Predicate{ .addr = end_addr });
|
||||
const end = Zld.findFirst(macho.relocation_info, relocs, start, Predicate{ .addr = start_addr });
|
||||
const start = MachO.findFirst(macho.relocation_info, relocs, 0, Predicate{ .addr = end_addr });
|
||||
const end = MachO.findFirst(macho.relocation_info, relocs, start, Predicate{ .addr = start_addr });
|
||||
|
||||
return relocs[start..end];
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user