Merge pull request #25 from bitemyapp/parity/21-umbrella-noreloc

Order the umbrella commands and flag an anchors-only segment as ld-prime does
This commit is contained in:
Rui Ueyama authored and GitHub committed 2026-09-30 13:04:01 +09:00
commit 78047514e8
5 files changed
+42 -6

No files matched your search

+31 -6
View File
@@ -327,6 +327,26 @@ fn create_segment_cmd<E: Target>(ctx: &Context<E>, seg: &OutputSegment) -> Vec<u
if seg.name == "__DATA_CONST" {
cmd.flags = SG_READ_ONLY;
}
// A segment of nothing but -add_empty_section anchors has nothing
// to relocate; ld-prime flags it SG_NORELOC. Only that option, not
// an empty section a `section$start$` boundary symbol conjured, and
// not an empty segment such as __PAGEZERO (no sections at all).
if !seg.chunks.is_empty()
&& seg.chunks.iter().all(|&id| match id {
ChunkId::SectCreate(i) => {
let h = &ctx.sectcreate_sections[i as usize].hdr;
h.size == 0
&& ctx
.args
.add_empty_section
.iter()
.any(|(seg, sect)| seg == h.segname && sect == &h.sectname)
}
_ => false,
})
{
cmd.flags |= SG_NORELOC;
}
let mut buf = to_vec(&cmd);
for hdr in sects {
@@ -569,12 +589,6 @@ pub fn create_load_commands<E: Target>(ctx: &Context<E>) -> Vec<Vec<u8>> {
if ctx.args.output_type == MH_DYLIB {
vec.push(create_id_dylib_cmd(ctx));
if let Some(name) = &ctx.args.umbrella {
vec.push(create_string_cmd(LC_SUB_FRAMEWORK, name));
}
for client in &ctx.args.allowable_clients {
vec.push(create_string_cmd(LC_SUB_CLIENT, client));
}
}
// Chained fixups replace the classic dyld info; the export trie
@@ -608,6 +622,17 @@ pub fn create_load_commands<E: Target>(ctx: &Context<E>) -> Vec<Vec<u8>> {
vec.push(create_load_dylib_cmd(dylib));
}
// The umbrella commands follow the libraries, clients first, as
// ld-prime orders them.
if ctx.args.output_type == MH_DYLIB {
for client in &ctx.args.allowable_clients {
vec.push(create_string_cmd(LC_SUB_CLIENT, client));
}
if let Some(name) = &ctx.args.umbrella {
vec.push(create_string_cmd(LC_SUB_FRAMEWORK, name));
}
}
for rpath in &ctx.args.rpaths {
vec.push(create_string_cmd(LC_RPATH, rpath));
}
+1
View File
@@ -200,6 +200,7 @@ pub const BIND_SPECIAL_DYLIB_WEAK_LOOKUP: i32 = -3;
pub const BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: u8 = 0x30;
// Segment flags
pub const SG_NORELOC: u32 = 0x4;
pub const SG_READ_ONLY: u32 = 0x10;
// Bind opcodes, for the LC_DYLD_INFO bind stream. Each opcode byte holds
+3
View File
@@ -9,3 +9,6 @@ $CC --ld-path=$mold -o $t/exe $t/a.o -Wl,-add_empty_section,__FOO,__foo
otool -l $t/exe | grep 'segname __FOO'
otool -l $t/exe | grep 'sectname __foo'
# The segment of only such anchors is flagged SG_NORELOC, as ld-prime
# flags it.
otool -l $t/exe | grep -A9 'segname __FOO' | grep 'flags 0x4'
+2
View File
@@ -14,6 +14,8 @@ EOF
$CC --ld-path=$mold -shared -o $t/libsub.dylib $t/a.o \
-Wl,-umbrella,Big -Wl,-allowable_client,friend
otool -l $t/libsub.dylib | grep 'client friend'
# The umbrella commands follow the libraries, clients first (ld-prime).
[ "$(otool -l $t/libsub.dylib | grep '^ *cmd ' | awk '{print $2}' | grep -E 'LC_LOAD_DYLIB|LC_SUB' | uniq | tr '\n' ' ')" = "LC_LOAD_DYLIB LC_SUB_CLIENT LC_SUB_FRAMEWORK " ]
# A random client is rejected.
not $CC --ld-path=$mold -o $t/exe $t/b.o $t/libsub.dylib 2> $t/log
+5
View File
@@ -24,3 +24,8 @@ EOF
$CC --ld-path=$mold -o $t/exe $t/a.o
$t/exe > /dev/null
# A __FOO segment conjured by a section$start boundary symbol is not an
# -add_empty_section anchor: its segment carries no SG_NORELOC (0x0),
# as ld-prime writes it.
otool -l $t/exe > $t/lc
[ "$(awk '/segname __FOO/{g=1} g&&/^ *flags/{print $2; exit}' $t/lc)" = 0x0 ]