mirror of
https://github.com/ziglang/zig.git
synced 2026-01-05 04:53:17 +00:00
zld: move should_rebase logic into Symbol
This commit is contained in:
parent
dbd2eb7c7f
commit
555b66c255
@ -339,6 +339,7 @@ const TextBlockParser = struct {
|
||||
zld: *Zld,
|
||||
nlists: []NlistWithIndex,
|
||||
index: u32 = 0,
|
||||
match: Zld.MatchingSection,
|
||||
|
||||
fn peek(self: *TextBlockParser) ?NlistWithIndex {
|
||||
return if (self.index + 1 < self.nlists.len) self.nlists[self.index + 1] else null;
|
||||
@ -405,6 +406,8 @@ const TextBlockParser = struct {
|
||||
const senior_nlist = aliases.pop();
|
||||
const senior_sym = self.zld.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;
|
||||
|
||||
const start_addr = senior_nlist.nlist.n_value - self.section.addr;
|
||||
const end_addr = if (next_nlist) |n| n.nlist.n_value - self.section.addr else self.section.size;
|
||||
@ -417,6 +420,11 @@ const TextBlockParser = struct {
|
||||
try out.ensureTotalCapacity(aliases.items.len);
|
||||
for (aliases.items) |alias| {
|
||||
out.appendAssumeCapacity(alias.index);
|
||||
|
||||
const sym = self.zld.locals.items[alias.index];
|
||||
const reg = &sym.payload.regular;
|
||||
reg.segment_id = self.match.seg;
|
||||
reg.section_id = self.match.sect;
|
||||
}
|
||||
break :blk out.toOwnedSlice();
|
||||
} else null;
|
||||
@ -439,6 +447,18 @@ const TextBlockParser = struct {
|
||||
try self.object.parseRelocs(self.zld, relocs, block, start_addr);
|
||||
}
|
||||
|
||||
const is_zerofill = blk: {
|
||||
const tseg = self.zld.load_commands.items[self.match.seg].Segment;
|
||||
const tsect = tseg.sections.items[self.match.sect];
|
||||
const tsect_type = sectionType(tsect);
|
||||
break :blk tsect_type == macho.S_ZEROFILL or
|
||||
tsect_type == macho.S_THREAD_LOCAL_ZEROFILL or
|
||||
tsect_type == macho.S_THREAD_LOCAL_VARIABLES;
|
||||
};
|
||||
if (is_zerofill) {
|
||||
mem.set(u8, block.code, 0);
|
||||
}
|
||||
|
||||
self.index += 1;
|
||||
|
||||
return block;
|
||||
@ -511,28 +531,16 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
|
||||
.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.warn("deduping definition of {s} in {s}", .{ sym.name, self.name.? });
|
||||
continue;
|
||||
}
|
||||
}
|
||||
reg.segment_id = match.seg;
|
||||
reg.section_id = match.sect;
|
||||
}
|
||||
|
||||
if (block.aliases) |aliases| {
|
||||
for (aliases) |alias| {
|
||||
const sym = zld.locals.items[alias];
|
||||
const reg = &sym.payload.regular;
|
||||
reg.segment_id = match.seg;
|
||||
reg.section_id = match.sect;
|
||||
const sym = zld.locals.items[block.local_sym_index];
|
||||
const reg = &sym.payload.regular;
|
||||
if (reg.file) |file| {
|
||||
if (file != self) {
|
||||
log.warn("deduping definition of {s} in {s}", .{ sym.name, self.name.? });
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
@ -587,6 +595,18 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
|
||||
try self.parseRelocs(zld, relocs, block, 0);
|
||||
}
|
||||
|
||||
const is_zerofill = blk: {
|
||||
const tseg = zld.load_commands.items[match.seg].Segment;
|
||||
const tsect = tseg.sections.items[match.sect];
|
||||
const tsect_type = sectionType(tsect);
|
||||
break :blk tsect_type == macho.S_ZEROFILL or
|
||||
tsect_type == macho.S_THREAD_LOCAL_ZEROFILL or
|
||||
tsect_type == macho.S_THREAD_LOCAL_VARIABLES;
|
||||
};
|
||||
if (is_zerofill) {
|
||||
mem.set(u8, block.code, 0);
|
||||
}
|
||||
|
||||
if (zld.last_text_block) |last| {
|
||||
last.next = block;
|
||||
block.prev = last;
|
||||
|
||||
@ -2,6 +2,7 @@ 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;
|
||||
|
||||
@ -57,6 +58,8 @@ pub const Regular = struct {
|
||||
|
||||
local_sym_index: u32 = 0,
|
||||
|
||||
should_rebase: bool = false,
|
||||
|
||||
pub const Linkage = enum {
|
||||
translation_unit,
|
||||
linkage_unit,
|
||||
@ -74,6 +77,9 @@ pub const Regular = struct {
|
||||
if (self.weak_ref) {
|
||||
try std.fmt.format(writer, ".weak_ref, ", .{});
|
||||
}
|
||||
if (self.should_rebase) {
|
||||
try std.fmt.format(writer, ".should_rebase, ", .{});
|
||||
}
|
||||
if (self.file) |file| {
|
||||
try std.fmt.format(writer, ".file = {s}, ", .{file.name.?});
|
||||
}
|
||||
@ -108,8 +114,8 @@ pub const Proxy = struct {
|
||||
/// Dynamic binding info - spots within the final
|
||||
/// executable where this proxy is referenced from.
|
||||
bind_info: std.ArrayListUnmanaged(struct {
|
||||
segment_id: u16,
|
||||
address: u64,
|
||||
local_sym_index: u32,
|
||||
offset: u32,
|
||||
}) = .{},
|
||||
|
||||
/// Dylib where to locate this symbol.
|
||||
@ -198,6 +204,17 @@ pub fn isTemp(symbol: Symbol) bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
pub fn needsTlvOffset(self: Symbol, zld: *Zld) bool {
|
||||
if (self.payload != .regular) return false;
|
||||
|
||||
const reg = self.payload.regular;
|
||||
const seg = zld.load_command.items[reg.segment_id].Segment;
|
||||
const sect = seg.sections.items[reg.section_id];
|
||||
const sect_type = commands.sectionType(sect);
|
||||
|
||||
return sect_type == macho.S_THREAD_LOCAL_VARIABLES;
|
||||
}
|
||||
|
||||
pub fn asNlist(symbol: *Symbol, strtab: *StringTable) !macho.nlist_64 {
|
||||
const n_strx = try strtab.getOrPut(symbol.name);
|
||||
const nlist = nlist: {
|
||||
|
||||
@ -107,8 +107,6 @@ locals: std.ArrayListUnmanaged(*Symbol) = .{},
|
||||
imports: std.ArrayListUnmanaged(*Symbol) = .{},
|
||||
globals: std.StringArrayHashMapUnmanaged(*Symbol) = .{},
|
||||
|
||||
threadlocal_offsets: std.ArrayListUnmanaged(TlvOffset) = .{}, // TODO merge with Symbol abstraction
|
||||
local_rebases: std.ArrayListUnmanaged(Pointer) = .{},
|
||||
stubs: std.ArrayListUnmanaged(*Symbol) = .{},
|
||||
got_entries: std.ArrayListUnmanaged(*Symbol) = .{},
|
||||
|
||||
@ -197,8 +195,6 @@ pub fn init(allocator: *Allocator) !Zld {
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Zld) void {
|
||||
self.threadlocal_offsets.deinit(self.allocator);
|
||||
self.local_rebases.deinit(self.allocator);
|
||||
self.stubs.deinit(self.allocator);
|
||||
self.got_entries.deinit(self.allocator);
|
||||
|
||||
@ -225,8 +221,6 @@ pub fn deinit(self: *Zld) void {
|
||||
}
|
||||
self.dylibs.deinit(self.allocator);
|
||||
|
||||
self.globals.deinit(self.allocator);
|
||||
|
||||
for (self.imports.items) |sym| {
|
||||
sym.deinit(self.allocator);
|
||||
self.allocator.destroy(sym);
|
||||
@ -239,6 +233,7 @@ pub fn deinit(self: *Zld) void {
|
||||
}
|
||||
self.locals.deinit(self.allocator);
|
||||
|
||||
self.globals.deinit(self.allocator);
|
||||
self.strtab.deinit();
|
||||
}
|
||||
|
||||
@ -290,7 +285,6 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg
|
||||
// try self.allocateDataSegment();
|
||||
// self.allocateLinkeditSegment();
|
||||
// try self.allocateSymbols();
|
||||
// try self.allocateProxyBindAddresses();
|
||||
// try self.flush();
|
||||
}
|
||||
|
||||
@ -449,7 +443,7 @@ fn updateMetadata(self: *Zld) !void {
|
||||
}
|
||||
}
|
||||
|
||||
const MatchingSection = struct {
|
||||
pub const MatchingSection = struct {
|
||||
seg: u16,
|
||||
sect: u16,
|
||||
};
|
||||
@ -1140,31 +1134,6 @@ fn allocateSymbols(self: *Zld) !void {
|
||||
}
|
||||
}
|
||||
|
||||
fn allocateProxyBindAddresses(self: *Zld) !void {
|
||||
for (self.objects.items) |object| {
|
||||
for (object.sections.items) |sect| {
|
||||
const relocs = sect.relocs orelse continue;
|
||||
|
||||
for (relocs) |rel| {
|
||||
if (rel.@"type" != .unsigned) continue; // GOT is currently special-cased
|
||||
if (rel.target != .symbol) continue;
|
||||
|
||||
const sym = object.symbols.items[rel.target.symbol];
|
||||
if (sym.payload != .proxy) continue;
|
||||
|
||||
const target_map = sect.target_map orelse continue;
|
||||
const target_seg = self.load_commands.items[target_map.segment_id].Segment;
|
||||
const target_sect = target_seg.sections.items[target_map.section_id];
|
||||
|
||||
try sym.payload.proxy.bind_info.append(self.allocator, .{
|
||||
.segment_id = target_map.segment_id,
|
||||
.address = target_sect.addr + target_map.offset + rel.offset,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn writeStubHelperCommon(self: *Zld) !void {
|
||||
const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
|
||||
const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?];
|
||||
@ -1748,72 +1717,6 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {
|
||||
args.source_source_sect_addr = sect.inner.addr;
|
||||
args.source_target_sect_addr = source_sect.inner.addr;
|
||||
}
|
||||
|
||||
const sect_type = sectionType(target_sect);
|
||||
const should_rebase = rebase: {
|
||||
if (!unsigned.is_64bit) break :rebase false;
|
||||
|
||||
// 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 (self.data_segment_cmd_index) |idx| {
|
||||
if (target_map.segment_id == idx) {
|
||||
break :blk true;
|
||||
}
|
||||
}
|
||||
if (self.data_const_segment_cmd_index) |idx| {
|
||||
if (target_map.segment_id == idx) {
|
||||
break :blk true;
|
||||
}
|
||||
}
|
||||
break :blk false;
|
||||
};
|
||||
|
||||
if (!is_right_segment) break :rebase false;
|
||||
if (sect_type != macho.S_LITERAL_POINTERS and
|
||||
sect_type != macho.S_REGULAR)
|
||||
{
|
||||
break :rebase false;
|
||||
}
|
||||
if (rel.target == .symbol) {
|
||||
const sym = object.symbols.items[rel.target.symbol];
|
||||
if (sym.payload == .proxy) {
|
||||
break :rebase false;
|
||||
}
|
||||
}
|
||||
|
||||
break :rebase true;
|
||||
};
|
||||
|
||||
if (should_rebase) {
|
||||
try self.local_rebases.append(self.allocator, .{
|
||||
.offset = source_addr - target_seg.inner.vmaddr,
|
||||
.segment_id = target_map.segment_id,
|
||||
});
|
||||
}
|
||||
|
||||
// TLV is handled via a separate offset mechanism.
|
||||
// Calculate the offset to the initializer.
|
||||
if (sect_type == macho.S_THREAD_LOCAL_VARIABLES) tlv: {
|
||||
// TODO we don't want to save offset to tlv_bootstrap
|
||||
if (mem.eql(u8, object.symbols.items[rel.target.symbol].name, "__tlv_bootstrap")) break :tlv;
|
||||
|
||||
const base_addr = blk: {
|
||||
if (self.tlv_data_section_index) |index| {
|
||||
const tlv_data = target_seg.sections.items[index];
|
||||
break :blk tlv_data.addr;
|
||||
} else {
|
||||
const tlv_bss = target_seg.sections.items[self.tlv_bss_section_index.?];
|
||||
break :blk tlv_bss.addr;
|
||||
}
|
||||
};
|
||||
// Since we require TLV data to always preceed TLV bss section, we calculate
|
||||
// offsets wrt to the former if it is defined; otherwise, wrt to the latter.
|
||||
try self.threadlocal_offsets.append(self.allocator, .{
|
||||
.source_addr = args.source_addr,
|
||||
.offset = args.target_addr - base_addr,
|
||||
});
|
||||
}
|
||||
},
|
||||
.got_page, .got_page_off, .got_load, .got, .pointer_to_got => {
|
||||
const dc_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
|
||||
@ -1839,34 +1742,6 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {
|
||||
try rel.resolve(args);
|
||||
}
|
||||
}
|
||||
|
||||
log.debug("writing contents of '{s},{s}' section from '{s}' from 0x{x} to 0x{x}", .{
|
||||
segname,
|
||||
sectname,
|
||||
object.name,
|
||||
target_sect_off,
|
||||
target_sect_off + sect.code.len,
|
||||
});
|
||||
|
||||
if (sectionType(target_sect) == macho.S_ZEROFILL or
|
||||
sectionType(target_sect) == macho.S_THREAD_LOCAL_ZEROFILL or
|
||||
sectionType(target_sect) == macho.S_THREAD_LOCAL_VARIABLES)
|
||||
{
|
||||
log.debug("zeroing out '{s},{s}' from 0x{x} to 0x{x}", .{
|
||||
segmentName(target_sect),
|
||||
sectionName(target_sect),
|
||||
target_sect_off,
|
||||
target_sect_off + sect.code.len,
|
||||
});
|
||||
|
||||
// Zero-out the space
|
||||
var zeroes = try self.allocator.alloc(u8, sect.code.len);
|
||||
defer self.allocator.free(zeroes);
|
||||
mem.set(u8, zeroes, 0);
|
||||
try self.file.?.pwriteAll(zeroes, target_sect_off);
|
||||
} else {
|
||||
try self.file.?.pwriteAll(sect.code, target_sect_off);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
const std = @import("std");
|
||||
const aarch64 = @import("../../codegen/aarch64.zig");
|
||||
const assert = std.debug.assert;
|
||||
const commands = @import("commands.zig");
|
||||
const log = std.log.scoped(.reloc);
|
||||
const macho = std.macho;
|
||||
const math = std.math;
|
||||
@ -567,14 +568,60 @@ pub const Parser = struct {
|
||||
const index = @intCast(u32, self.zld.got_entries.items.len);
|
||||
out_rel.target.got_index = index;
|
||||
try self.zld.got_entries.append(self.zld.allocator, out_rel.target);
|
||||
log.debug("adding GOT entry for symbol {s} at index {}", .{ out_rel.target.name, index });
|
||||
}
|
||||
|
||||
if (out_rel.payload == .branch) {
|
||||
log.debug("adding GOT entry for symbol {s} at index {}", .{ out_rel.target.name, index });
|
||||
} else if (out_rel.payload == .unsigned) {
|
||||
const sym = out_rel.target;
|
||||
switch (sym.payload) {
|
||||
.proxy => {
|
||||
try sym.payload.proxy.bind_info.append(self.zld.allocator, .{
|
||||
.local_sym_index = self.block.local_sym_index,
|
||||
.offset = out_rel.offset,
|
||||
});
|
||||
},
|
||||
else => {
|
||||
const source_sym = self.zld.locals.items[self.block.local_sym_index];
|
||||
const source_reg = &source_sym.payload.regular;
|
||||
const seg = self.zld.load_commands.items[source_reg.segment_id].Segment;
|
||||
const sect = seg.sections.items[source_reg.section_id];
|
||||
const sect_type = commands.sectionType(sect);
|
||||
|
||||
const should_rebase = rebase: {
|
||||
if (!out_rel.payload.unsigned.is_64bit) break :rebase false;
|
||||
|
||||
// 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 (self.zld.data_segment_cmd_index) |idx| {
|
||||
if (source_reg.segment_id == idx) {
|
||||
break :blk true;
|
||||
}
|
||||
}
|
||||
if (self.zld.data_const_segment_cmd_index) |idx| {
|
||||
if (source_reg.segment_id == idx) {
|
||||
break :blk true;
|
||||
}
|
||||
}
|
||||
break :blk false;
|
||||
};
|
||||
|
||||
if (!is_right_segment) break :rebase false;
|
||||
if (sect_type != macho.S_LITERAL_POINTERS and
|
||||
sect_type != macho.S_REGULAR)
|
||||
{
|
||||
break :rebase false;
|
||||
}
|
||||
|
||||
break :rebase true;
|
||||
};
|
||||
source_reg.should_rebase = should_rebase;
|
||||
},
|
||||
}
|
||||
} else if (out_rel.payload == .branch) blk: {
|
||||
const sym = out_rel.target;
|
||||
|
||||
if (sym.stubs_index != null) continue;
|
||||
if (sym.payload != .proxy) continue;
|
||||
if (sym.stubs_index != null) break :blk;
|
||||
if (sym.payload != .proxy) break :blk;
|
||||
|
||||
const index = @intCast(u32, self.zld.stubs.items.len);
|
||||
sym.stubs_index = index;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user