dlopen() crashes with DSI on first call (GCC13/adtools toolchain libstdc++.so) + dlerror() never reports the real dlopen() failure reason
- Langage dominant
- C
- Étoiles
- 19
- Forks
- 7
- Merge moyen
- 1 j 11 h
- PR mergées (30 j)
- 6
Description
BODY:
Hi, I'm Maijestro. I'm porting a C/C++ application (Xash3D FWGS engine) to AmigaOS4 using clib4 (`-mcrt=clib4`), built with the `walkero/amigagccondocker:os4-gcc13` Docker image (GCC 13.4.0, adtools build), tested under QEMU (Pegasos 2, AmigaOS 4.1 Final Edition, clib4.library V2.2, elf.library V54.5).
I ran into two issues around `dlopen()`/`dlerror()` that I wanted to report together since they're related. Full write-up with disassembly and crash logs attached as a Word doc.
## Bug A: dlopen() DSI crash on the very first call
### Repro (minimal, ~10 lines)
```c
#include
#include
int main(void)
{
printf("before dlopen\n");
fflush(stdout);
void *h = dlopen("anything.so", RTLD_NOW);
printf("after dlopen: %p\n", h); /* never reached */
return 0;
}
```
Built with:
```
ppc-amigaos-gcc -mcrt=clib4 -O0 -g -o repro_minimal repro_minimal.c
```
Run from an AmigaOS4 Shell with a `libstdc++.so` from the GCC13 toolchain itself (`/opt/ppc-amigaos/ppc-amigaos/lib/clib4/libstdc++.so`, tried both unstripped ~30MB debug build and stripped ~3.8MB release build — both crash identically) placed alongside the binary. `anything.so` doesn't even need to exist — the crash happens inside `dlopen()` itself.
### Result
DSI (Data Storage Interrupt) exception on the first `dlopen()` call. GrimReaper crash log:
```
Crash occured in module libc.so at address 0x7F5D1360
Type of crash: DSI (Data Storage Interrupt) exception
Data Address (dar): 0x00000070
Stack trace:
module .../SObjs/libc.so at 0x7F5D1360
module .../SObjs/libstdc++.so at 0x7F33FFA0
native kernel module elf.library.kmod+0x0000a628
module LIBS:clib4.library ...
repro_minimal:main()+0x...
repro_minimal:clib4_start()+0x20c
repro_minimal:_start()+0x30
PPC disassembly at crash site:
lis r11, ... ; load high half of IClib4 address
lwz r0, ...(r11) ; load IClib4 pointer -> r0
*lwzx r11,r12,r0 ; index into IClib4 struct -> CRASH (dar=0x70)
mtctr r11
bctr
```
### Root cause (as far as I could tell from the clib4 source)
This matches the `__Clib4Call` trampoline in `library/shared_library/stubs_common.c`, which jumps through a function pointer loaded from the global `IClib4` struct pointer. `IClib4` is supposed to be populated by `__init_clib4_so()`, registered as a constructor in both `.ctors` and `.init_array` (per the comment in that file: "crtbegin.o is not linked into .so files").
I checked the toolchain-provided `libc.so` (from the Docker image's SDK, `/opt/ppc-amigaos/ppc-amigaos/SDK/clib4/lib/libc.so`) with `objdump -s -j .ctors -j .init_array` — both sections are empty/zeroed, so `__init_clib4_so()` never runs automatically, `IClib4` stays NULL, and `__Clib4Call` dereferences a NULL-ish pointer (matches `dar=0x70`, a small struct offset).
Control test: a trivial clib4 program that only calls `printf()` (no `dlopen()`) runs fine on the exact same SDK/toolchain/target — so this isn't a blanket SDK breakage, it specifically seems tied to the first `dlopen()` call.
I did notice the README says shared objects "needs the beta elf.library not yet released to public" — if that's the actual cause here (our elf.library is V54.5, the public release), it would be great to get that confirmed, since right now there's no way to tell from the crash itself that a newer elf.library is required.
### Impact
Any clib4/AmigaOS4 app built with this GCC13/adtools toolchain that links C++ (pulling in the toolchain's own `libstdc++.so`) and calls `dlopen()` crashes unconditionally on first use.
## Bug B: dlerror() never reports the real dlopen() failure reason
### Observed
When `dlopen()` fails on a library that demonstrably exists on disk, `errno` is correctly set to `ENOENT`, but `dlerror()` called right after always returns NULL:
```
dlopen("PROGDIR:valve/dlls/hl_amigaos4_ppc.so") FAILED, errno=2
Sys_Warn: can't initialize dlls/hl_amigaos4_ppc.so: <- empty, this is dlerror() output
```
### Root cause
`library/stdlib/dlopen.c`, on `DLOpen()` returning NULL, only sets `errno`:
```c
result = DLOpen(__clib4->__dl_root_handle, path_name, flags);
if (result == NULL) {
SHOWMSG("DLOpen returned NULL");
__set_errno_r(__clib4, ENOENT); /* errno set here */
/* __clib4->__elf_error_code is NOT set */
}
```
Compare to `dlsym.c`, which correctly propagates the `Elf32_Error`:
```c
error = DLSym(__clib4->__dl_root_handle, lookup_handle, symbol_name, &symbol_data);
if (error != ELF32_NO_ERROR) {
__clib4->__elf_error_code = error; /* correctly propagated */
goto out;
}
```
Since `dlerror()` (`library/stdlib/dlerror.c`) only ever reads `__clib4->__elf_error_code`, and that's left at `ELF32_NO_ERROR` after a `dlopen()` failure, `dlerror()` is useless for diagnosing `dlopen()` failures specifically — it works fine for `dlsym()`/`dlclose()` failures.
I'm not sure if `DLOpen()` (the elf.library wrapper) even exposes a granular error code the way `DLSym()`/`DLClose()` do — if not, this might need a fix on the elf.library side too (something like an `IElf->GetElfError()` call after a failed `DLOpen()`).
---
Happy to test patches or provide more info / logs — I have a QEMU (Pegasos 2) AmigaOS 4.1 FE setup ready to go. Full write-up with more detail and an appendix on an unrelated libstdc++.so SjLj/DWARF unwinding ABI mismatch we ran into while investigating this (old AmigaOS4.1 system libstdc++.so vs. this GCC13 toolchain's libgcc.so) is attached.
Guide de contribution
Aucun guide de contribution indexé pour ce dépôt
Évaluation
Cette issue n'a pas encore été évaluée.