Skip to content

Commit 688adba

Browse files
committed
Avoid libc surface under __BARE_METAL__
- __ASSERT halts via infinite loop instead of exit() (avoids newlib stdio teardown chain). - hexdump / dump_trace become no-ops. - New __weak rand_u32() helper: xorshift on bare-metal, libc rand() on hosted. randint() now uses it unconditionally so bare-metal callers get a working PRNG. Signed-off-by: Siddharth Chandrasekaran <sidcha.dev@gmail.com>
1 parent 7fd46d4 commit 688adba

3 files changed

Lines changed: 73 additions & 8 deletions

File tree

‎include/utils/assert.h‎

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,24 @@ extern "C" {
1818

1919
#include <zephyr/sys/__assert.h>
2020

21-
#else /* __ZEPHYR__ */
21+
#elif defined(__BARE_METAL__)
22+
23+
/*
24+
* Bare-metal: avoid exit()/atexit cleanup (pulls in newlib stdio teardown).
25+
* printf is expected to be provided by the platform; on failure, halt.
26+
*/
27+
#define __ASSERT_PRINT(fmt, ...) printf(fmt, ##__VA_ARGS__)
28+
#define __ASSERT(test, fmt, ...) \
29+
do { \
30+
if (!(test)) { \
31+
__ASSERT_PRINT("ASSERTION FAIL [%s] @ %s:%d\n\t" fmt "\n", \
32+
STR(test), __FILE__, __LINE__, \
33+
##__VA_ARGS__); \
34+
for (;;) { } \
35+
} \
36+
} while (0)
37+
38+
#else /* everything else expects libc */
2239

2340
#define __ASSERT_PRINT(fmt, ...) printf(fmt, ##__VA_ARGS__)
2441

‎include/utils/utils.h‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,10 +200,22 @@ typedef uint32_t tick_t;
200200
typedef uint64_t tick_t;
201201
#endif
202202

203+
/**
204+
* @brief Return a non-cryptographic random uint32.
205+
*
206+
* Bare-metal builds use an internal xorshift; hosted builds forward to
207+
* libc rand(). Cryptographic callers must NOT use this.
208+
*
209+
* Defined as __weak: platforms that can do better (e.g. an STM32 RNG
210+
* peripheral, an mbedTLS DRBG, /dev/urandom) should provide their own
211+
* strong override.
212+
*/
213+
__weak uint32_t rand_u32(void);
214+
203215
/**
204216
* @brief Return random number between 0 and `limit` both inclusive.
205217
*
206-
* Note: the random number generator must be pre-seeded.
218+
* Backed by rand_u32(). Non-cryptographic.
207219
*/
208220
int randint(int limit);
209221

‎src/utils.c‎

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,35 @@ _Static_assert(IS_ENABLED(_IS_ENABLED_SELFTEST_OFF) == 0,
1919
"IS_ENABLED(): undefined flag must evaluate to 0");
2020
#undef _IS_ENABLED_SELFTEST_ON
2121

22+
__weak uint32_t rand_u32(void)
23+
{
24+
#ifdef __BARE_METAL__
25+
/*
26+
* libc's rand() references _impure_ptr, which pulls newlib's
27+
* default FILE table (__sf) and the stdio teardown chain
28+
* (_close_r/_lseek_r/_read_r/_write_r) into the link even when
29+
* nothing else uses stdio. Replace it with a self-contained
30+
* xorshift — same non-cryptographic quality as rand(), zero libc
31+
* dependency.
32+
*/
33+
static uint32_t s_state = 0x9E3779B9u;
34+
uint32_t x = s_state;
35+
36+
x ^= x << 13;
37+
x ^= x >> 17;
38+
x ^= x << 5;
39+
s_state = x ? x : 1u;
40+
return x;
41+
#else
42+
return (uint32_t)rand();
43+
#endif
44+
}
45+
2246
int randint(int limit)
2347
{
24-
int r;
25-
int divisor = RAND_MAX / (limit + 1);
48+
uint32_t span = (uint32_t)limit + 1u;
2649

27-
do {
28-
r = rand() / divisor;
29-
} while (r > limit);
30-
return r;
50+
return (int)(rand_u32() % span);
3151
}
3252

3353
uint32_t round_up_pow2(uint32_t v)
@@ -54,6 +74,18 @@ int num_digits_in_number(int num)
5474
return digits;
5575
}
5676

77+
#ifdef __BARE_METAL__
78+
79+
__format_printf(3, 4)
80+
void hexdump(const void *p, size_t len, const char *fmt, ...)
81+
{
82+
ARG_UNUSED(p);
83+
ARG_UNUSED(len);
84+
ARG_UNUSED(fmt);
85+
}
86+
87+
#else
88+
5789
__format_printf(3, 4)
5890
void hexdump(const void *p, size_t len, const char *fmt, ...)
5991
{
@@ -92,6 +124,8 @@ void hexdump(const void *p, size_t len, const char *fmt, ...)
92124
printf("\n");
93125
}
94126

127+
#endif /* __BARE_METAL__ */
128+
95129
#if (defined(_WIN32) || defined(_WIN64))
96130
#define WIN32_LEAN_AND_MEAN
97131
#include <Windows.h>
@@ -283,6 +317,8 @@ void dump_trace(void)
283317
puts("");
284318
free(strings);
285319
}
320+
#elif defined(__BARE_METAL__)
321+
void dump_trace(void) { }
286322
#else
287323
void dump_trace(void)
288324
{

0 commit comments

Comments
 (0)