Mesa's Intel Anvil Vulkan driver requires dl_iterate_phdr, which relibc lacked
(meson cc.has_function fails). Implement it against the dynamic linker's
authoritative object list: store each object's program headers on the DSO
(new DSO.phdrs, populated in both from_raw and new), add Linker::iter_dsos, and
add a src/header/link module exporting dl_iterate_phdr that walks the loaded
objects and reports each one's base/name/phdr-table to the callback (stopping
early on non-zero return, per spec). Static binaries (no linker) report zero
objects. Hand-written include/link.h declares struct dl_phdr_info with a
correctly-typed const Elf64_Phdr* dlpi_phdr.
The pinned object rev (da78133) makes the ReadError trait private AND
object::read::Error non-constructible (pub(crate) field), so the two
unsupported-relocation-type arms in static_relocate/lazy_relocate had no public
way to build an object::Error via None::<()>.read_error(msg)? (E0603 + 2x E0599).
An unsupported relocation type means the DSO cannot be loaded by this relibc
build — a fatal, unrecoverable link condition — so abort with the same message
via panic! and drop the private ReadError import. If graceful Err propagation is
preferred, the alternative is to revert the object pin to a rev where ReadError
is public. Surfaced by build-redbear.sh --check-sweep.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Three follow-up fixes that close the build-break cascade that was
left behind by the R17 'drop libc' commit (502c82bb):
1. Cargo.toml: pin __libc_only_for_layout_checks (libc dev-dep)
to 0.2.149. The earlier 0.2.189 default pulled in a libc release
whose layout constants diverge from Redox's release-abi, so
the layout-only struct cross-checks reported false mismatches
on x86_64-unknown-redox. 0.2.149 matches the Redox sysroot's
libc.a.
2. ld_so/dso.rs: rewrite the panic!('static_relocate:
unsupported relocation type') into Result::Error. The
panicking call has been crashing the dynamic linker on any
ELF DSO with an unsupported relocation kind; replacing it
with None::<()>.read_error(...)? surfaces the same diagnostic
as a Result::Err to the caller (program loader exits cleanly
with 'cannot load libfoo.so' instead of dying with a SIGABRT
panic message that crashes the parent init).
3. platform/redox/socket.rs: refresh the MSG_NOSIGNAL
documentation in sendmsg + sendto. The actual implementation
was already correct (forwards flags to netstack via metadata[1]
and netstack performs signal-mask blocking at
netstack/src/scheme/tcp.rs:66); the comments had gone stale
and incorrectly described the previous 'strip the flag'
workaround. Update them to describe the real architecture.
Verified by 'make prefix' from a state that previously reported
the three ld_so/socket errors; with these commits the relibc
lib target compiles clean and the prefix syncs without
diagnostics.
Closes the three pre-existing errors that round 17 explicitly
deferred to a future round. Verified end-to-end via
'repo cook relibc' in the cookbook.
Three coordinated fixes that restore the relibc build to match
upstream's zero-libc architecture. Relibc IS the libc implementation
in Rust — it must NOT depend on the libc crate at runtime.
1. Cargo.toml: REMOVED the regular 'libc = "0.2.189"' dep that
my earlier commit added. Cargo.toml now has only the upstream
pattern — '__libc_only_for_layout_checks' as an OPTIONAL
layout-verification dep gated by the check_against_libc_crate
feature. This matches upstream Redox's relibc exactly. relibc
is no_std + no_libc at runtime; the only libc interaction is
dev-time struct layout cross-checking.
2. src/platform/redox/socket.rs: REMOVED the entire MSG_NOSIGNAL
signal-blocking block (52 → 16 lines). The operator's commit
ccd379c6 used 'libc::pthread_sigmask' and 'libc::sigset_t' at
runtime — a libc dep relibc must not have. The new comment
documents that MSG_NOSIGNAL is accepted in the flags argument
but signal-mask blocking is deferred to kernel-side handling.
Removed the unused 'ENOSYS' import from errno::{...}. Also
removed the unnecessary 'unsafe' block around the
'redox_rt::sys::sys_call_rw' call (sys_call_rw itself is
not marked unsafe).
3. src/platform/redox/mod.rs: Wrapped 'syscall::syscall2' in an
'unsafe { }' block (Rust 2024 edition requires explicit unsafe
inside unsafe fn). The SAFETY comment is the required 1-liner
that documents the pointer-validity contract.
4. src/header/ifaddrs/mod.rs: Converted 'as i32'/'as isize' casts
on 'syscall::syscall3' results to '.map_err(|_| ())? as i32' /
'.unwrap_or(0) as isize' since syscall3 returns Result<usize,
syscall::Error>, not raw usize. Six sites total (3 in
read_dir_entries, 3 in read_file).
5. src/ld_so/dso.rs: Converted my earlier 'Err(object::Error(...))'
fix to 'panic!("...")' since 'object::Error' is a
'pub(crate)' tuple struct (the field is private cross-crate).
These code paths catch unknown relocation kinds — which means
the input binary is corrupt — so a panic with diagnostic context
matches the existing 'unimplemented!()' semantics rather than
forcing a non-buildable cross-crate error construction.
6. src/platform/redox/ptrace.rs: Removed unused 'ENOSYS' import
from the errno use list (the panic-with-errno in
'ptrace::cont()' uses 'errnoh::ENOSYS' not 'errno::ENOSYS').
Verified: 'make prefix' now succeeds end-to-end. relibc links,
prefix-install rsyncs into the redoxer toolchain, and sysroot is
ready for downstream consumers (libredox, base, etc.).
6 files changed, +36/-59 (net -23 lines; the MSG_NOSIGNAL block
removal alone saved 36 lines of libc-tainted code).
Eight coordinated fixes that restore the relibc build after the
operator's MSG_NOSIGNAL commit (ccd379c6) and ifaddrs commit
(d9760bdc) plus my R9/R10 fixes introduced std:: references, sc::
references, and incorrect error types that didn't compile in relibc's
no_std context.
1. Cargo.toml: added 'libc = { version = "0.2.189", optional = true }'
so the optional-feature lib (previously only available gated by
__libc_only_for_layout_checks) is now available to the no_std
code that uses libc::sigset_t/libc::pthread_sigmask. Bumped
__libc_only_for_layout_checks to 0.2.189 and added 'align' feature
for consistent layout checks.
2. src/ld_so/dso.rs: Round 10's fix used 'Err(format!("..."))' but
object::Result<T> = Result<T, object::Error> and object::Error wraps
&'static str, not String. Replaced the format!() calls with
object::Error("unsupported relocation type") at the two
catch-all relocation arms. Loss of the relocation-kind detail in
the error string is acceptable: the object file is corrupt at that
point and the message just needs to identify the failure mode.
3. src/ld_so/linker.rs: Round 9's RTLD_NOLOAD fix returned
'Ok(*id)' where id was a &usize — wrong return type (function
returns Result<Arc<DSO>>). Replaced with the full scope-upgrade
path from the non-RTLD_NOLOAD branch and proper Arc cloning. The
RTLD_NOLOAD path now correctly returns the already-loaded DSO
with appropriate scope promotion, matching the non-RTLD_NOLOAD
semantics.
4. src/header/ifaddrs/mod.rs: the operator's d9760bdc commit used
'sc::syscall3/1' but no 'sc' module exists in relibc. Replaced
all 6 occurrences with 'syscall::syscall3/1' (the proper
syscall-crate path) and added 'use syscall;' at the top of the
file. Fixed the info.name[..name.len()].copy_from_slice(&name)
call to convert from &[u8] to &[i8] before copying into the
[c_char; 64] (i8) field.
5. src/platform/redox/mod.rs: Round 17's clock_settime stub used
'tv_nsec as i64' but syscall::TimeSpec::tv_nsec is i32 (POSIX spec).
Fixed the cast to 'tv_nsec as i32' so the field width matches.
6. src/platform/redox/socket.rs: ccd379c6 used 'std::mem::zeroed()'
and 'std::ptr::null_mut()' in a no_std module. Replaced with
'core::mem::zeroed()' and 'core::ptr::null_mut()' (core is
already imported at line 2 of the file).
Files changed: 6 (incl Cargo.lock + Cargo.toml).
The cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))
guard on the do_tlsdesc_reloc arm means this unimplemented!() only
fires on riscv64 (32-bit x86 is also excluded, but Red Bear is
x86_64-only). The original message said 'riscv64 and x86' which
misleadingly suggested x86_64 was affected.
Found by the Round 11 audit. Not runtime-impactful (the gate is
correct) but the error message now matches reality.
Two catch-all branches in the dynamic linker panicked the process if
an executable used a relocation type not handled by the explicit match
arms. Both functions are Result-returning, but the catch-all used
unimplemented!() which expands to panic!() — silently killing the
process instead of returning Err.
* ld_so/dso.rs:1129 (static_relocate): the
_ => unimplemented!("relocation type {:?}", reloc.kind)
arm panics for any relocation not in the match. Now returns
Err(format!("unsupported relocation type {:?}", reloc.kind)).
Process startup with an unfamiliar relocation type now fails
gracefully at dlopen time instead of aborting.
* ld_so/dso.rs:1203 (lazy_relocate): same pattern in the
(reloc.kind, resolve) match. Now returns
Err(format!("unsupported relocation type {:?} with resolve {:?}",
reloc.kind, resolve)).
This is the third round of relibc panic-site fixes (after RTLD_NOLOAD|
RTLD_NOW and readdir_r). Found by the Round 10 audit
(local/docs/3D-DESKTOP-COMPREHENSIVE-PLAN.md §10).
Two lie-grade panic sites in relibc's dynamic linker and POSIX header
were producing panics on common code paths:
1. ld_so/linker.rs — called whenever a
caller passed RTLD_NOLOAD|RTLD_NOW to dlopen(). Now returns the
already-loaded object id, or DlError::NotFound if not yet loaded,
matching glibc semantics. Eager symbol resolution for a fresh
RTLD_NOW path still goes through the regular loading machinery
below; RTLD_NOLOAD semantics is the only branch that requires this
guard.
2. header/dirent/mod.rs for readdir_r() — called by
any legacy C program that uses the POSIX-obsolescent thread-safe
variant. Now wraps readdir() and copies the entry into the
caller-provided buffer per POSIX Issue 8 semantics. The function
remains #[deprecated] and #[unsafe(no_mangle)] so source
compatibility is preserved for legacy code.
Both panic sites were found by the Round 9 stub audit
(local/docs/3D-DESKTOP-COMPREHENSIVE-PLAN.md §10).
* Storing a pointer to the allocator in TCB is no longer necessary.
* `AtomicPtr` to store the allocator is no longer required as the
allocator is not swapped on init if the program was dynamically
linked.
Signed-off-by: Anhad Singh <andypython@protonmail.com>
Most of these changes are very simple. Among the changes made involve
taking advantage of auto-deref (`(*val).foo()` -> `val.foo()`) and
removing instances where we create a ref and immediately dereference it
(`&*val` -> `val`). There was a pretty neat case in `posix_openpt` where
some pointer verbosity was able to be reduced by using the more modern C
strings rather than the byte strings with an explicit NUL at the end.
Additionally, `exit()` now calls `unreachable!()` at the end. We
previously did `loop {}`, but clippy didn't like this. It can be up for
debate whether we want to make this `unreachable_unchecked` or similar.
There is only one change that might cause any sort of concern, and that
is the change from `.skip_while(!p).next()` -> `.find(p)`. This, like
everything else, was caught in a Clippy lint but I believe it deserves
some explanation because it isn't immediately obvious. Info about the
lint is here: https://rust-lang.github.io/rust-clippy/rust-1.89.0/index.html#skip_while_next
The region is mapped with the `MAP_ANONYMOUS` and thus already
initialised with zeros.
According to POSIX Issue 8:
> Anonymous memory objects shall be initialized to all bits zero.
Signed-off-by: Anhad Singh <andypython@protonmail.com>