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:
Rui UeyamaandClaude Opus 5.5 committed 2026-10-08 17:48:37 +09:00
1 parent ce2f56bec8
commit 1107fc340e
15 files changed
+120 -123

No files matched your search

+14 -15
View File
@@ -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),
+8 -8
View File
@@ -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));
}
+1 -1
View File
@@ -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());
}
+2 -2
View File
@@ -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
View File
@@ -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());
}
}
}
+2 -3
View File
@@ -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
View File
@@ -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)
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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).
+3 -3
View File
@@ -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
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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: {}",
+78
View File
@@ -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]