mirror of
https://github.com/rui314/mold.git
synced 2026-11-07 09:16:04 -10:00
Make the symbol addresses Symbol methods, as mold has them
A symbol's address, its GOT slot's, its stub's, the pointer its stub jumps through and where a branch to it goes were Context methods taking the symbol's id (sym_addr, sym_got_addr, sym_stub_addr, stub_ptr_addr, branch_target_addr). mold's are Symbol methods taking the context: addr, got_addr, plt_addr and gotplt_addr. These are now Symbol::addr, got_addr, stub_addr (mold's plt_addr, keeping the Mach-O name of the section), stub_ptr_addr (its gotplt_addr) and branch_target_addr. objc_msgsend_got_addr stays on Context, as it names no symbol. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
ce2f56bec8
commit
1107fc340e
15 files changed
+120
-123
No files matched your search
+14
-15
@@ -840,7 +840,7 @@ impl Target for Arm64 {
|
||||
let off = stubs::entry_offset::<Self>(i as u32);
|
||||
let ent = &mut buf[off as usize..];
|
||||
let ent_addr = addr + off;
|
||||
let ptr_addr = ctx.stub_ptr_addr(i, sym);
|
||||
let ptr_addr = ctx.symbols[sym].stub_ptr_addr(ctx, i);
|
||||
if !adrp_reaches(ptr_addr, ent_addr) {
|
||||
crate::error!(
|
||||
"stub for {}: ADRP out of range, from 0x{ent_addr:08X} to its pointer at 0x{ptr_addr:08X}",
|
||||
@@ -864,7 +864,7 @@ impl Target for Arm64 {
|
||||
// ldr x16, [x16, dyld_stub_binder@GOTPAGEOFF]
|
||||
// br x16
|
||||
let private = ctx.isec_addr(ctx.stub_helper.dyld_private_isec as usize);
|
||||
let binder = ctx.sym_got_addr(ctx.stub_helper.dyld_stub_binder.unwrap());
|
||||
let binder = ctx.symbols[ctx.stub_helper.dyld_stub_binder.unwrap()].got_addr(ctx);
|
||||
write32(&mut buf[0..], 0x9000_0011 | page_offset(private, addr));
|
||||
write32(&mut buf[4..], 0x9100_0231 | ((private as u32 & 0xfff) << 10));
|
||||
write32(&mut buf[8..], 0xa9bf_47f0);
|
||||
@@ -886,7 +886,7 @@ impl Target for Arm64 {
|
||||
|
||||
fn write_objc_stubs(ctx: &Context<Self>, addr: u64, buf: &mut [u8]) {
|
||||
if ctx.args.objc_stubs_small {
|
||||
let msgsend = ctx.branch_target_addr(ctx.objc_stubs.msgsend_sym.unwrap());
|
||||
let msgsend = ctx.symbols[ctx.objc_stubs.msgsend_sym.unwrap()].branch_target_addr(ctx);
|
||||
for i in 0..ctx.objc_stubs.symbols.len() {
|
||||
let off = objc_stubs::entry_offset(ctx, i as u32);
|
||||
let ent = &mut buf[off as usize..];
|
||||
@@ -924,7 +924,7 @@ impl Target for Arm64 {
|
||||
}
|
||||
|
||||
fn write_lazy_helpers(ctx: &Context<Self>, addr: u64, buf: &mut [u8]) {
|
||||
let lazy_load = ctx.sym_stub_addr(ctx.lazy_helpers.dyld_lazy_load.unwrap());
|
||||
let lazy_load = ctx.symbols[ctx.lazy_helpers.dyld_lazy_load.unwrap()].stub_addr(ctx);
|
||||
let header = ctx.mach_header.hdr.addr;
|
||||
for h in &ctx.lazy_helpers.helpers {
|
||||
let insn = HelperInsn { base: addr + h.offset as u64 };
|
||||
@@ -1051,7 +1051,7 @@ impl Target for Arm64 {
|
||||
let (insn, rd) = (HelperInsn { base: addr + h.offset as u64 }, reg as u32);
|
||||
let flag = ctx.isec_addr(delay.dlopens[h.dlopen as usize].flag as usize);
|
||||
let helper = delay.dlopen_helper_addr(h.dlopen as usize);
|
||||
let slot = ctx.sym_got_addr(h.sym);
|
||||
let slot = ctx.symbols[h.sym].got_addr(ctx);
|
||||
let code = [
|
||||
insn.adrp(0, rd, flag),
|
||||
insn.add(rd, flag),
|
||||
@@ -1068,7 +1068,7 @@ impl Target for Arm64 {
|
||||
for d in &delay.dlopens {
|
||||
let insn = HelperInsn { base: addr + d.offset as u64 };
|
||||
let (name, flag) = (ctx.isec_addr(d.string as usize), ctx.isec_addr(d.flag as usize));
|
||||
let dlopen = ctx.sym_stub_addr(delay.dlopen_sym.unwrap());
|
||||
let dlopen = ctx.symbols[delay.dlopen_sym.unwrap()].stub_addr(ctx);
|
||||
let mut code = DLOPEN_HELPER;
|
||||
code[16] = insn.adrp(16, 0, name);
|
||||
code[17] = insn.add(0, name);
|
||||
@@ -1181,7 +1181,7 @@ impl Target for Arm64 {
|
||||
for (i, &sym) in syms.iter().enumerate() {
|
||||
let ent = &mut buf[i * 12..];
|
||||
let ent_addr = addr + i as u64 * 12;
|
||||
let target = ctx.branch_target_addr(sym);
|
||||
let target = ctx.symbols[sym].branch_target_addr(ctx);
|
||||
|
||||
// adrp x16, target@PAGE; add x16, x16, target@PAGEOFF; br x16
|
||||
write32(&mut ent[0..], 0x9000_0010 | page_offset(target, ent_addr));
|
||||
@@ -1361,7 +1361,7 @@ impl Target for Arm64 {
|
||||
}
|
||||
let sym = ctx.reloc_target_sym(obj, r);
|
||||
let s = match sym {
|
||||
Some(id) => ctx.branch_target_addr(id),
|
||||
Some(id) => ctx.symbols[id].branch_target_addr(ctx),
|
||||
None => s,
|
||||
};
|
||||
let t = s.wrapping_add_signed(a);
|
||||
@@ -1431,9 +1431,8 @@ impl Target for Arm64 {
|
||||
// __thread_vars descriptor. Other loads keep loading the
|
||||
// address from __got.
|
||||
ARM64_RELOC_GOT_LOAD_PAGE21 | ARM64_RELOC_TLVP_LOAD_PAGE21 => {
|
||||
let id = ctx.reloc_target_sym(obj, r).unwrap();
|
||||
let t =
|
||||
if ctx.symbols[id].can_relax_got(ctx) { s } else { ctx.sym_got_addr(id) };
|
||||
let sym = &ctx.symbols[ctx.reloc_target_sym(obj, r).unwrap()];
|
||||
let t = if sym.can_relax_got(ctx) { s } else { sym.got_addr(ctx) };
|
||||
check_adrp(ctx, isec_id, r, p, t.wrapping_add_signed(a));
|
||||
write_adrp(loc, t.wrapping_add_signed(a), p);
|
||||
}
|
||||
@@ -1441,9 +1440,9 @@ impl Target for Arm64 {
|
||||
// load's 64-bit add as one relaxed already, and refuses
|
||||
// any other instruction.
|
||||
ARM64_RELOC_GOT_LOAD_PAGEOFF12 | ARM64_RELOC_TLVP_LOAD_PAGEOFF12 => {
|
||||
let id = ctx.reloc_target_sym(obj, r).unwrap();
|
||||
if !ctx.symbols[id].can_relax_got(ctx) {
|
||||
let g = ctx.sym_got_addr(id);
|
||||
let sym = &ctx.symbols[ctx.reloc_target_sym(obj, r).unwrap()];
|
||||
if !sym.can_relax_got(ctx) {
|
||||
let g = sym.got_addr(ctx);
|
||||
if let Err(size) = write_add_ldst(loc, g.wrapping_add_signed(a)) {
|
||||
report_ldst_alignment(ctx, isec_id, r, size);
|
||||
}
|
||||
@@ -1462,7 +1461,7 @@ impl Target for Arm64 {
|
||||
}
|
||||
}
|
||||
ARM64_RELOC_POINTER_TO_GOT => {
|
||||
let g = ctx.sym_got_addr(ctx.reloc_target_sym(obj, r).unwrap());
|
||||
let g = ctx.symbols[ctx.reloc_target_sym(obj, r).unwrap()].got_addr(ctx);
|
||||
write32(loc, g.wrapping_add_signed(a).wrapping_sub(p) as u32);
|
||||
}
|
||||
_ => fatal!("unsupported relocation type: {}", r.ty),
|
||||
|
||||
@@ -171,7 +171,7 @@ fn write_branch8(
|
||||
/// lea lazy_ptr(%rip), %r11
|
||||
/// jmp dyld_stub_binding_helper
|
||||
fn write_legacy_stub_helper(ctx: &Context<X86_64>, addr: u64, buf: &mut [u8]) {
|
||||
let helper = ctx.stub_helper.binding_helper.map(|id| ctx.sym_addr(id));
|
||||
let helper = ctx.stub_helper.binding_helper.map(|id| ctx.symbols[id].addr(ctx));
|
||||
if helper.is_none() {
|
||||
crate::error!("stub helper: target 'dyld_stub_binding_helper' does not have address");
|
||||
}
|
||||
@@ -256,7 +256,7 @@ impl Target for X86_64 {
|
||||
let off = stubs::entry_offset::<Self>(i as u32);
|
||||
let ent = &mut buf[off as usize..];
|
||||
let ent_addr = addr + off;
|
||||
let ptr_addr = ctx.stub_ptr_addr(i, sym);
|
||||
let ptr_addr = ctx.symbols[sym].stub_ptr_addr(ctx, i);
|
||||
let disp = ptr_addr.wrapping_sub(ent_addr + 6) as i64;
|
||||
if i32::try_from(disp).is_err() {
|
||||
let p = ent_addr + 2;
|
||||
@@ -285,7 +285,7 @@ impl Target for X86_64 {
|
||||
// jmp *dyld_stub_binder@GOTPCREL(%rip)
|
||||
// nop
|
||||
let private = ctx.isec_addr(ctx.stub_helper.dyld_private_isec as usize);
|
||||
let binder = ctx.sym_got_addr(ctx.stub_helper.dyld_stub_binder.unwrap());
|
||||
let binder = ctx.symbols[ctx.stub_helper.dyld_stub_binder.unwrap()].got_addr(ctx);
|
||||
buf[0..3].copy_from_slice(&[0x4c, 0x8d, 0x1d]);
|
||||
write32(&mut buf[3..], private.wrapping_sub(addr + 7) as u32);
|
||||
buf[7..9].copy_from_slice(&[0x41, 0x53]);
|
||||
@@ -323,7 +323,7 @@ impl Target for X86_64 {
|
||||
}
|
||||
|
||||
fn write_lazy_helpers(ctx: &Context<Self>, addr: u64, buf: &mut [u8]) {
|
||||
let lazy_load = ctx.sym_stub_addr(ctx.lazy_helpers.dyld_lazy_load.unwrap());
|
||||
let lazy_load = ctx.symbols[ctx.lazy_helpers.dyld_lazy_load.unwrap()].stub_addr(ctx);
|
||||
let header = ctx.mach_header.hdr.addr;
|
||||
for h in &ctx.lazy_helpers.helpers {
|
||||
let size = Self::lazy_helper_size(h.kind) as usize;
|
||||
@@ -411,7 +411,7 @@ impl Target for X86_64 {
|
||||
let ent = &mut buf[h.offset as usize..h.offset as usize + size];
|
||||
let base = addr + h.offset as u64;
|
||||
write_delay_check(ctx, ent, base, h.dlopen);
|
||||
let slot = ctx.sym_got_addr(h.sym);
|
||||
let slot = ctx.symbols[h.sym].got_addr(ctx);
|
||||
match h.kind {
|
||||
DelayUse::Load { reg, .. } => {
|
||||
ent[19..22].copy_from_slice(&movq_rip(reg));
|
||||
@@ -425,7 +425,7 @@ impl Target for X86_64 {
|
||||
}
|
||||
}
|
||||
}
|
||||
let dlopen = ctx.sym_stub_addr(delay.dlopen_sym.unwrap());
|
||||
let dlopen = ctx.symbols[delay.dlopen_sym.unwrap()].stub_addr(ctx);
|
||||
for d in &delay.dlopens {
|
||||
let size = Self::DLOPEN_HELPER_SIZE as usize;
|
||||
let ent = &mut buf[d.offset as usize..d.offset as usize + size];
|
||||
@@ -748,7 +748,7 @@ impl Target for X86_64 {
|
||||
// A pc-relative fixup that can't reach is an error.
|
||||
X86_64_RELOC_BRANCH => {
|
||||
let s = match ctx.reloc_target_sym(obj, r) {
|
||||
Some(id) => ctx.branch_target_addr(id),
|
||||
Some(id) => ctx.symbols[id].branch_target_addr(ctx),
|
||||
None => s,
|
||||
};
|
||||
let t = s.wrapping_add_signed(a);
|
||||
@@ -771,7 +771,7 @@ impl Target for X86_64 {
|
||||
write32(loc, rip32_displacement(ctx, isec_id, r, p, t));
|
||||
}
|
||||
X86_64_RELOC_GOT_LOAD | X86_64_RELOC_GOT | X86_64_RELOC_TLV => {
|
||||
let g = ctx.sym_got_addr(ctx.reloc_target_sym(obj, r).unwrap());
|
||||
let g = ctx.symbols[ctx.reloc_target_sym(obj, r).unwrap()].got_addr(ctx);
|
||||
let t = g.wrapping_add_signed(a);
|
||||
write32(loc, rip32_displacement(ctx, isec_id, r, p, t));
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ pub fn copy_buf<E: Target>(ctx: &Context<E>, buf: &mut [u8]) {
|
||||
|
||||
if let Some(personality) = cie.personality {
|
||||
let cell_addr = base_addr + cie.output_offset as u64 + cie.personality_offset as u64;
|
||||
let val = ctx.sym_got_addr(personality).wrapping_sub(cell_addr) as u32;
|
||||
let val = ctx.symbols[personality].got_addr(ctx).wrapping_sub(cell_addr) as u32;
|
||||
let cell = off + cie.personality_offset as usize;
|
||||
buf[cell..cell + 4].copy_from_slice(&val.to_le_bytes());
|
||||
}
|
||||
|
||||
@@ -179,9 +179,9 @@ fn exports<E: Target>(
|
||||
}
|
||||
let addr = if sym.is_absolute(ctx) {
|
||||
flags |= EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE;
|
||||
ctx.sym_addr(id)
|
||||
sym.addr(ctx)
|
||||
} else {
|
||||
ctx.sym_addr(id) - base
|
||||
sym.addr(ctx) - base
|
||||
};
|
||||
Some((sym.name(), Export::Addr { flags, addr }))
|
||||
})
|
||||
|
||||
+1
-1
@@ -77,7 +77,7 @@ pub fn copy_buf<E: Target>(ctx: &Context<E>, buf: &mut [u8]) {
|
||||
};
|
||||
for (i, &id) in ctx.got.got_syms.iter().enumerate() {
|
||||
if !binds(id) {
|
||||
buf[i * 8..i * 8 + 8].copy_from_slice(&ctx.sym_addr(id).to_le_bytes());
|
||||
buf[i * 8..i * 8 + 8].copy_from_slice(&ctx.symbols[id].addr(ctx).to_le_bytes());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,10 +41,9 @@ pub fn build<E: Target>(ctx: &Context<E>) -> (Vec<u8>, Vec<u32>) {
|
||||
let mut buf = Vec::new();
|
||||
let mut offsets = Vec::with_capacity(ctx.stubs.lazy.len());
|
||||
for &i in &ctx.stubs.lazy {
|
||||
let id = ctx.stubs.symbols[i as usize];
|
||||
let sym = &ctx.symbols[ctx.stubs.symbols[i as usize]];
|
||||
offsets.push(buf.len() as u32);
|
||||
let (seg, off) = segment_and_offset(ctx, ctx.stub_ptr_addr(i as usize, id));
|
||||
let sym = &ctx.symbols[id];
|
||||
let (seg, off) = segment_and_offset(ctx, sym.stub_ptr_addr(ctx, i as usize));
|
||||
let flags = if sym.is_weak_ref() { BIND_SYMBOL_FLAGS_WEAK_IMPORT } else { 0 };
|
||||
let ops = [
|
||||
Op::SegOffset(seg, off),
|
||||
|
||||
+1
-1
@@ -695,7 +695,7 @@ fn create_routines_cmd<E: Target>(ctx: &Context<E>, id: SymbolId) -> Vec<u8> {
|
||||
let cmd = RoutinesCommand64 {
|
||||
cmd: LC_ROUTINES_64,
|
||||
cmdsize: size_of::<RoutinesCommand64>() as u32,
|
||||
init_address: ctx.sym_addr(id),
|
||||
init_address: ctx.symbols[id].addr(ctx),
|
||||
..Default::default()
|
||||
};
|
||||
to_vec(&cmd)
|
||||
|
||||
@@ -80,7 +80,7 @@ pub fn rebase_locations<E: Target>(ctx: &Context<E>) -> Vec<u64> {
|
||||
// weak-lookup stub's GOT slot is rebased with the GOT).
|
||||
for &i in &ctx.stubs.lazy {
|
||||
let i = i as usize;
|
||||
locs.push(ctx.stub_ptr_addr(i, ctx.stubs.symbols[i]));
|
||||
locs.push(ctx.symbols[ctx.stubs.symbols[i]].stub_ptr_addr(ctx, i));
|
||||
}
|
||||
|
||||
// GOT slots that hold local addresses. (Legacy LINKEDIT's dyld
|
||||
|
||||
@@ -218,7 +218,7 @@ impl<'a, E: Target> Places<'a, E> {
|
||||
(isec.offset != u32::MAX).then(|| self.chunk(chunk, isec.offset as u64))
|
||||
}
|
||||
|
||||
/// Where a symbol's address lies, as Context::sym_addr resolves it
|
||||
/// Where a symbol's address lies, as Symbol::addr resolves it
|
||||
/// (a dylib symbol at its stub); None for an absolute symbol. The
|
||||
/// linker's own sectionless symbols are the layout boundaries and
|
||||
/// the mach header's names (___dso_handle, __mh_*_header).
|
||||
|
||||
@@ -240,7 +240,7 @@ impl StabPlan {
|
||||
let mut ent = stab.ent;
|
||||
if let Some(id) = stab.value_of {
|
||||
if addr.0 != id {
|
||||
addr = (id, ctx.sym_addr(id));
|
||||
addr = (id, ctx.symbols[id].addr(ctx));
|
||||
}
|
||||
ent.value = addr.1;
|
||||
}
|
||||
@@ -1163,7 +1163,7 @@ pub fn write_symtab<E: Target>(
|
||||
let strtab = BufPtr(strtab.as_mut_ptr());
|
||||
let strtab = &strtab;
|
||||
|
||||
// Millions of entries, each wanting a sym_addr lookup for its
|
||||
// Millions of entries, each wanting an addr lookup for its
|
||||
// value: emit them in parallel blocks.
|
||||
const BLOCK: usize = 4096;
|
||||
let (locals, externs) = symtab.entries.split_at(start);
|
||||
@@ -1176,7 +1176,7 @@ pub fn write_symtab<E: Target>(
|
||||
for (i, ((msym, sym), name)) in ents.iter().zip(names).enumerate() {
|
||||
let mut msym = *msym;
|
||||
if let Some(id) = sym {
|
||||
msym.value = ctx.sym_addr(*id);
|
||||
msym.value = ctx.symbols[*id].addr(ctx);
|
||||
}
|
||||
msym.write_to(&mut out[i * size_of::<MachSym>()..]);
|
||||
// SAFETY: layout_strings gave each name a range of
|
||||
|
||||
@@ -67,7 +67,7 @@ pub fn copy_buf<E: Target>(ctx: &Context<E>, buf: &mut [u8]) {
|
||||
let personality_off = u32::from_le_bytes(sec.contents[12..16].try_into().unwrap()) as usize;
|
||||
for (i, &sym) in sec.personalities.iter().enumerate() {
|
||||
let off = personality_off + i * 4;
|
||||
let val = ctx.sym_got_addr(sym).wrapping_sub(base) as u32;
|
||||
let val = ctx.symbols[sym].got_addr(ctx).wrapping_sub(base) as u32;
|
||||
buf[off..off + 4].copy_from_slice(&val.to_le_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
+2
-83
@@ -39,7 +39,6 @@ use crate::chunks::{
|
||||
ChunkHeader, ChunkId, OutputMachHeader, OutputSection, OutputSectionId, OutputSegment,
|
||||
};
|
||||
use crate::cmdline::Args;
|
||||
use crate::error;
|
||||
use crate::input_files::{DylibFile, FileId, ObjectFile};
|
||||
use crate::input_sections::{InputSection, Reloc, RelocTarget};
|
||||
use crate::macho::{MachSection, S_THREAD_LOCAL_REGULAR, S_THREAD_LOCAL_ZEROFILL, bytes_to_name};
|
||||
@@ -544,64 +543,6 @@ impl<E: Target> Context<E> {
|
||||
self.chunk_header(chunk).addr + isec.offset as u64
|
||||
}
|
||||
|
||||
/// Returns the output address of a symbol.
|
||||
pub fn sym_addr(&self, id: SymbolId) -> u64 {
|
||||
let sym = &self.symbols[id];
|
||||
match sym.file() {
|
||||
// A DTrace symbol, never defined, is at address 0 for
|
||||
// ld-prime: where a branch that is no probe site goes.
|
||||
None => {
|
||||
if !crate::dtrace::is_dtrace_symbol(sym.name()) {
|
||||
error!("undefined symbol: {sym}");
|
||||
}
|
||||
0
|
||||
}
|
||||
Some(FileId::Obj(_)) => {
|
||||
if let Some(isec) = sym.input_section().map(|i| i as usize) {
|
||||
self.isec_addr(isec) + sym.value
|
||||
} else if let Some(idx) = sym.objc_stub_idx(&self.symbols) {
|
||||
self.objc_stubs.hdr.addr + crate::chunks::objc_stubs::entry_offset(self, idx)
|
||||
} else {
|
||||
sym.value
|
||||
}
|
||||
}
|
||||
// A branch to a dylib symbol goes through its stub, or for
|
||||
// a lazily loaded dylib's, its call helper. Other
|
||||
// references to dylib symbols are filled in by dyld; the
|
||||
// relocation scan has already validated them.
|
||||
Some(FileId::Dylib(_)) => {
|
||||
if sym.stub_idx(&self.symbols).is_some() {
|
||||
self.sym_stub_addr(id)
|
||||
} else if let Some(idx) = sym.lazy_stub_idx(&self.symbols) {
|
||||
self.lazy_helpers.helper_addr(idx as usize)
|
||||
} else if let Some(idx) = sym.delay_stub_idx(&self.symbols) {
|
||||
self.delay_init.stub_addr::<E>(idx as usize)
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the address of a symbol's __stubs entry.
|
||||
pub fn sym_stub_addr(&self, id: SymbolId) -> u64 {
|
||||
let idx = self.symbols[id].stub_idx(&self.symbols).unwrap();
|
||||
self.stubs.hdr.addr + crate::chunks::stubs::entry_offset::<E>(idx)
|
||||
}
|
||||
|
||||
/// The address of the pointer slot stub `i` (for symbol `id`)
|
||||
/// jumps through: its lazy pointer, or its GOT slot. A weak
|
||||
/// definition of this image always goes through its GOT slot (the
|
||||
/// lazy binder cannot do weak lookup), as in ld64.
|
||||
pub fn stub_ptr_addr(&self, i: usize, id: SymbolId) -> u64 {
|
||||
if self.args.lazy_binding && !self.symbols[id].binds_weak_lookup(self) {
|
||||
let slot = self.stubs.lazy.binary_search(&(i as u32)).unwrap();
|
||||
self.lazy_ptrs.slot_addr(slot)
|
||||
} else {
|
||||
self.sym_got_addr(id)
|
||||
}
|
||||
}
|
||||
|
||||
/// The library ordinal an interposable export binds with.
|
||||
pub fn export_bind_ordinal(&self) -> i32 {
|
||||
match self.args.flat_namespace {
|
||||
@@ -610,32 +551,10 @@ impl<E: Target> Context<E> {
|
||||
}
|
||||
}
|
||||
|
||||
/// The address a branch to `id` targets: the symbol's stub when it
|
||||
/// has one and dyld may redirect it, else the symbol itself.
|
||||
pub fn branch_target_addr(&self, id: SymbolId) -> u64 {
|
||||
if self.symbols[id].is_interposable(self)
|
||||
&& self.symbols[id].stub_idx(&self.symbols).is_some()
|
||||
{
|
||||
self.sym_stub_addr(id)
|
||||
} else {
|
||||
self.sym_addr(id)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the address of a symbol's __got slot, or for a lazily
|
||||
/// loaded dylib's symbol, its __lazy_load_got slot.
|
||||
pub fn sym_got_addr(&self, id: SymbolId) -> u64 {
|
||||
let sym = &self.symbols[id];
|
||||
match sym.got_idx(&self.symbols) {
|
||||
Some(idx) => self.got.slot_addr(idx as usize),
|
||||
None => self.lazy_load_got.slot_addr(sym.lazy_got_idx(&self.symbols).unwrap()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the address of the __got slot the objc stubs load
|
||||
/// _objc_msgSend from.
|
||||
pub fn objc_msgsend_got_addr(&self) -> u64 {
|
||||
self.sym_got_addr(self.objc_stubs.msgsend_sym.unwrap())
|
||||
self.symbols[self.objc_stubs.msgsend_sym.unwrap()].got_addr(self)
|
||||
}
|
||||
|
||||
/// Returns the symbol a relocation refers to, if it refers to one.
|
||||
@@ -669,7 +588,7 @@ impl<E: Target> Context<E> {
|
||||
/// Resolves a relocation target to its output address.
|
||||
pub fn reloc_target_addr(&self, obj: usize, rel: &Reloc) -> u64 {
|
||||
match rel.target() {
|
||||
RelocTarget::Sym(idx) => self.sym_addr(self.objs[obj].symbols[idx as usize]),
|
||||
RelocTarget::Sym(idx) => self.symbols[self.objs[obj].symbols[idx as usize]].addr(self),
|
||||
RelocTarget::Section(idx) => self.isec_addr(idx as usize),
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -83,7 +83,7 @@ impl ObjcRef {
|
||||
pub fn addr<E: Target>(self, ctx: &Context<E>) -> u64 {
|
||||
match self {
|
||||
ObjcRef::Isec(isec, off) => ctx.isec_addr(isec as usize) + off,
|
||||
ObjcRef::Sym(id, addend) => (ctx.sym_addr(id) as i64 + addend) as u64,
|
||||
ObjcRef::Sym(id, addend) => (ctx.symbols[id].addr(ctx) as i64 + addend) as u64,
|
||||
ObjcRef::TailSelref(n) => ctx.objc_stubs.selref_addr(ctx, n),
|
||||
ObjcRef::Null => 0,
|
||||
}
|
||||
|
||||
+4
-2
@@ -3666,8 +3666,10 @@ pub fn resolve_entry<E: Target>(ctx: &mut Context<E>) {
|
||||
// An entry point in a dylib (an app extension's
|
||||
// _NSExtensionMain): LC_MAIN must point into __TEXT, so it
|
||||
// names the symbol's stub, as ld64 does.
|
||||
Some(id) if ctx.symbols[id].is_imported() => ctx.entry_addr = ctx.sym_stub_addr(id),
|
||||
Some(id) if ctx.symbols[id].is_defined() => ctx.entry_addr = ctx.sym_addr(id),
|
||||
Some(id) if ctx.symbols[id].is_imported() => {
|
||||
ctx.entry_addr = ctx.symbols[id].stub_addr(ctx)
|
||||
}
|
||||
Some(id) if ctx.symbols[id].is_defined() => ctx.entry_addr = ctx.symbols[id].addr(ctx),
|
||||
_ => {
|
||||
error!(
|
||||
"undefined symbol for entry point: {}",
|
||||
|
||||
@@ -571,6 +571,84 @@ impl Symbol {
|
||||
|| self.name().starts_with(b"_OBJC_METACLASS_$_"))
|
||||
}
|
||||
|
||||
/// Returns the output address of the symbol.
|
||||
pub fn addr<E: Target>(&self, ctx: &Context<E>) -> u64 {
|
||||
match self.file() {
|
||||
// A DTrace symbol, never defined, is at address 0 for
|
||||
// ld-prime: where a branch that is no probe site goes.
|
||||
None => {
|
||||
if !crate::dtrace::is_dtrace_symbol(self.name()) {
|
||||
crate::error!("undefined symbol: {self}");
|
||||
}
|
||||
0
|
||||
}
|
||||
Some(FileId::Obj(_)) => {
|
||||
if let Some(isec) = self.input_section().map(|i| i as usize) {
|
||||
ctx.isec_addr(isec) + self.value
|
||||
} else if let Some(idx) = self.objc_stub_idx(&ctx.symbols) {
|
||||
ctx.objc_stubs.hdr.addr + crate::chunks::objc_stubs::entry_offset(ctx, idx)
|
||||
} else {
|
||||
self.value
|
||||
}
|
||||
}
|
||||
// A branch to a dylib symbol goes through its stub, or for
|
||||
// a lazily loaded dylib's, its call helper. Other
|
||||
// references to dylib symbols are filled in by dyld; the
|
||||
// relocation scan has already validated them.
|
||||
Some(FileId::Dylib(_)) => {
|
||||
if self.stub_idx(&ctx.symbols).is_some() {
|
||||
self.stub_addr(ctx)
|
||||
} else if let Some(idx) = self.lazy_stub_idx(&ctx.symbols) {
|
||||
ctx.lazy_helpers.helper_addr(idx as usize)
|
||||
} else if let Some(idx) = self.delay_stub_idx(&ctx.symbols) {
|
||||
ctx.delay_init.stub_addr::<E>(idx as usize)
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the address of the symbol's __got slot, or for a lazily
|
||||
/// loaded dylib's symbol, its __lazy_load_got slot.
|
||||
pub fn got_addr<E: Target>(&self, ctx: &Context<E>) -> u64 {
|
||||
match self.got_idx(&ctx.symbols) {
|
||||
Some(idx) => ctx.got.slot_addr(idx as usize),
|
||||
None => ctx.lazy_load_got.slot_addr(self.lazy_got_idx(&ctx.symbols).unwrap()),
|
||||
}
|
||||
}
|
||||
|
||||
/// The address of the pointer slot the symbol's stub, stub `i`,
|
||||
/// jumps through: its lazy pointer, or its GOT slot - mold's
|
||||
/// gotplt_addr. A weak definition of this image always goes
|
||||
/// through its GOT slot (the lazy binder cannot do weak lookup), as
|
||||
/// in ld64.
|
||||
pub fn stub_ptr_addr<E: Target>(&self, ctx: &Context<E>, i: usize) -> u64 {
|
||||
if ctx.args.lazy_binding && !self.binds_weak_lookup(ctx) {
|
||||
let slot = ctx.stubs.lazy.binary_search(&(i as u32)).unwrap();
|
||||
ctx.lazy_ptrs.slot_addr(slot)
|
||||
} else {
|
||||
self.got_addr(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the address of the symbol's __stubs entry - mold's
|
||||
/// plt_addr.
|
||||
pub fn stub_addr<E: Target>(&self, ctx: &Context<E>) -> u64 {
|
||||
let idx = self.stub_idx(&ctx.symbols).unwrap();
|
||||
ctx.stubs.hdr.addr + crate::chunks::stubs::entry_offset::<E>(idx)
|
||||
}
|
||||
|
||||
/// The address a branch to the symbol targets: its stub when it
|
||||
/// has one and dyld may redirect it, else the symbol itself.
|
||||
pub fn branch_target_addr<E: Target>(&self, ctx: &Context<E>) -> u64 {
|
||||
if self.is_interposable(ctx) && self.stub_idx(&ctx.symbols).is_some() {
|
||||
self.stub_addr(ctx)
|
||||
} else {
|
||||
self.addr(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
/// The address of a thunk entry for the symbol that a branch at `pc`
|
||||
/// can reach, if it has one - mold's thunk_addr.
|
||||
#[inline]
|
||||
|
||||
Reference in new issue
Block a user