/* clock_abi_probe.c — 时钟 ABI 最小探针(M11)。 * * 用途:在宿主或真机上一眼看出「编译器头文件声明的 time_t 宽度」与「libc 实际写入的 * struct timespec 宽度」是否一致——这正是 meow_ui_time_ms 真机故障的根因(详见 * sdk/CLOCK_ABI.md)。做法:先把 struct timespec 整块填 0xAA,再调 clock_gettime, * 看哪些字节被写回: * - 正确(time64:tv_sec 8B + tv_nsec 4B):偏移 0..11 被写,8..11 不再是 0xAA; * - 坏(libc 只做 o32 time32:只写 8B):偏移 8..11 仍是 0xAA → 退出码 2; * - 头/库宽度相反(头 8B、库写 16B)也会在偏移检查里暴露。 * * 构建(宿主): * gcc -Os -Wall -Wextra tools/clock_abi_probe.c -o clock_abi_probe * 构建(mipsel 静态,测裸 zig libc): * ~/.tools/zig-mipsel-cc -Os -static tools/clock_abi_probe.c -o clock_abi_probe * 构建(mipsel + SDK,测修复后的归档是否接管 clock_gettime): * ~/.tools/zig-mipsel-cc -Os -static -DMEOW_PROBE_WITH_SDK -I. -Iinclude \ * tools/clock_abi_probe.c meow_ui.a /lib/libz.a -lpthread -o clock_abi_probe_sdk * * 运行:./clock_abi_probe * 退出码:0=ABI 一致且时钟单调、量级合理;1=时钟值异常;2=libc 只写了 8 字节(ABI 不一致)。 */ #include #include #include #include #include #ifdef MEOW_PROBE_WITH_SDK #include "meow_ui.h" #endif #define PAD_BYTE 0xAA static uint64_t now_ms(void) { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); return (uint64_t)ts.tv_sec * 1000u + (uint64_t)ts.tv_nsec / 1000000u; } int main(void) { int rc = 0; struct timespec ts; unsigned char raw[sizeof(struct timespec)]; printf("sizeof(time_t)=%u sizeof(long)=%u sizeof(struct timespec)=%u\n", (unsigned)sizeof(time_t), (unsigned)sizeof(long), (unsigned)sizeof(struct timespec)); printf("offsetof(tv_sec)=%u offsetof(tv_nsec)=%u\n", (unsigned)offsetof(struct timespec, tv_sec), (unsigned)offsetof(struct timespec, tv_nsec)); memset(&ts, PAD_BYTE, sizeof ts); int r = clock_gettime(CLOCK_MONOTONIC, &ts); memcpy(raw, &ts, sizeof raw); printf("clock_gettime ret=%d tv_sec=%lld tv_nsec=%ld\n", r, (long long)ts.tv_sec, (long)ts.tv_nsec); printf("raw:"); for (unsigned i = 0; i < sizeof raw; i++) printf(" %02x", raw[i]); printf("\n"); if (r != 0) { printf("FAIL clock_gettime 失败\n"); return 1; } /* tv_nsec 所在 4 字节必须被 libc 写过 */ if (sizeof(struct timespec) > 8 && raw[8] == PAD_BYTE && raw[9] == PAD_BYTE && raw[10] == PAD_BYTE && raw[11] == PAD_BYTE) { printf("FAIL libc 只写了 8 字节 time32(头声明 %u 字节)→ ABI 不一致\n", (unsigned)sizeof(struct timespec)); rc = 2; } uint64_t a = now_ms(); uint64_t b = now_ms(); if (b < a || b - a > 5000 || b >= (1ULL << 40)) { printf("FAIL 毫秒值异常: a=%llu b=%llu\n", (unsigned long long)a, (unsigned long long)b); rc = rc ? rc : 1; } else { printf("ok now_ms a=%llu b=%llu\n", (unsigned long long)a, (unsigned long long)b); } #ifdef MEOW_PROBE_WITH_SDK uint64_t s1 = meow_ui_time_ms(); uint64_t s2 = meow_ui_time_ms(); printf("meow_ui_time_ms: %llu %llu\n", (unsigned long long)s1, (unsigned long long)s2); if (s2 < s1 || s2 - s1 > 5000 || s2 >= (1ULL << 40) || s2 == 0) { printf("FAIL meow_ui_time_ms 异常\n"); rc = rc ? rc : 1; } #endif printf(rc ? "== FAIL (rc=%d) ==\n" : "== PASS ==\n", rc); return rc; }