Unresolved atomics-related symbols when compiling for Armv5

I am trying to target a very specific device which uses a very old architecture, specifically, ArmV5TEJL which does not support multithreading or atomics

When compiling something like:

const std = @import("std");

pub fn main() !void {
	std.log.info("true awesomesauce", .{});
}

like this:

zig build-exe -target arm-linux-musl -mcpu=arm926ej_s zigtest.zig

it would blow up like this:

...
error: ld.lld: undefined symbol: __sync_val_compare_and_swap_4
    note: referenced by atomics.zig:173 (/home/nelson/.local/share/zigup/0.15.1/files/lib/compiler_rt/atomics.zig:173)
    note:               .cache/zig/o/4a90990682dd11096120b80ccb6e796b/libcompiler_rt_zcu.o:(__atomic_load_4) in archive .cache/zig/o/4a90990682dd11096120b80ccb6e796b/libcompiler_rt.a
    note: referenced by atomics.zig:316 (/home/nelson/.local/share/zigup/0.15.1/files/lib/compiler_rt/atomics.zig:316)
    note:               .cache/zig/o/4a90990682dd11096120b80ccb6e796b/libcompiler_rt_zcu.o:(__atomic_compare_exchange_4) in archive .cache/zig/o/4a90990682dd11096120b80ccb6e796b/libcompiler_rt.a
    note: referenced by atomic.zig:32 (/home/nelson/.local/share/zigup/0.15.1/files/lib/std/atomic.zig:32)
    note:               .cache/zig/tmp/9cc30e5291ef1d8d/zigtest_zcu.o:(Thread.Mutex.FutexImpl.tryLock)
    note: referenced 1 more times
error: ld.lld: undefined symbol: __sync_lock_test_and_set_1
    note: referenced by atomics.zig:204 (/home/nelson/.local/share/zigup/0.15.1/files/lib/compiler_rt/atomics.zig:204)
    note:               .cache/zig/o/4a90990682dd11096120b80ccb6e796b/libcompiler_rt_zcu.o:(__atomic_store_1) in archive .cache/zig/o/4a90990682dd11096120b80ccb6e796b/libcompiler_rt.a
    note: referenced by atomics.zig:271 (/home/nelson/.local/share/zigup/0.15.1/files/lib/compiler_rt/atomics.zig:271)
    note:               .cache/zig/o/4a90990682dd11096120b80ccb6e796b/libcompiler_rt_zcu.o:(__atomic_exchange_1) in archive .cache/zig/o/4a90990682dd11096120b80ccb6e796b/libcompiler_rt.a
error: ld.lld: undefined symbol: __sync_lock_test_and_set_2
    note: referenced by atomics.zig:204 (/home/nelson/.local/share/zigup/0.15.1/files/lib/compiler_rt/atomics.zig:204)
    note:               .cache/zig/o/4a90990682dd11096120b80ccb6e796b/libcompiler_rt_zcu.o:(__atomic_store_2) in archive .cache/zig/o/4a90990682dd11096120b80ccb6e796b/libcompiler_rt.a
    note: referenced by atomics.zig:271 (/home/nelson/.local/share/zigup/0.15.1/files/lib/compiler_rt/atomics.zig:271)
    note:               .cache/zig/o/4a90990682dd11096120b80ccb6e796b/libcompiler_rt_zcu.o:(__atomic_exchange_2) in archive .cache/zig/o/4a90990682dd11096120b80ccb6e796b/libcompiler_rt.a

any way to circumvent this? i’m trying to get this build to be static but i heard that there’s probably a library i can load up? also, as this device i’m targetting doesn’t even do multithreading… can’t I just NOP all of these?

The implementation of defaultLog uses a lock. Fortunately, according to the documentation, the implementation of log can be customized.

This makes sense, but what if I use a library that uses a lock internally? (which seems to be the case for a lot of stuff)

Is there a more general approach I could take?

Does compiling with -fsingle-threaded help? That should turn locks into noops.

nope, exact same errors

After reading the source code, in single_threaded mode, ordinary mutex does not involve atomic weights.

The reason for the lock problem of defaultLog is that its stderr_mutex happens to use Recursive Mutex.

This lock is not handled for single_threaded, so it involves atomicity.

I searched the standard library for Mutex.Recursive and found only one implementation, stderr_mutex. Therefore, only the code involving stderr might encounter issues in single_threaded mode. You were just unlucky to have used that particular place for testing. Most code using locks should not be a problem in single_threaded mode.

Additionally, implementing atomic instructions in non-atomic form in single_threaded mode is an accepted proposal, but has not yet been implemented.

2 Likes

oh wow! that’s in-depth! so should i just use another logging library? is this a problem unique to the logging library? i guess until the zig team implements the non-atomic instruction stuff

I think this is a problem with the standard library. The standard library should have provided an alternative implementation for ‘Mutex. Recursive’ under ‘single_threaded’, but it did not do so. You can propose an issue for this purpose.

thank you for the information! this was wildly educative, I made an issue here:

Have you tried implementing a custom logging function and using single_threaded? If the standard logging function is the only place this Recursive lock is in place, you could copy the body, remove the problematic code and get around this issue in the meantime.

In your main file:

pub const std_options: std.Options = .{
    .log_fn = customLogFn,
};
1 Like

Seems like I can’t even use the stdout :frowning:

const std = @import("std");

pub fn main() !void {
    const stdout = std.fs.File.stdout();
    try stdout.writeAll("Test 2!");
}

this snippet yields the exact same errors