iT邦幫忙

2021 iThome 鐵人賽

DAY 7
0

這篇我們將正式進入libc testing的部份,我們可以用以下方式來運行libc-test、並使用qemu linux-user來運行測項:
CROSS_COMPILE=riscv32-linux- CC=musl-gcc RUN_WRAP=$(which qemu-riscv32 make)

接下來,就會看到複數個syscall的fail,橫跨數個測資,他們分別是:

statfs
fstatfs
lseek
utimensat

這幾項的修復方式與上一篇相似,首先去尋找qemu當中的linux-user syscall 表: linux-user/riscv/syscall32_nr.h
我們可以發現目前與其他32平台一樣,stat系的須全部搬遷至time64_t的版本,即:

statfs64
fstatfs64
llseek
utimensat_time64 

在消掉 arch/riscv32/bits/syscall.h.in對應的舊syscall、與增添新的syscall與對應的syscall no後。
我們再去巡視了一下相關的程式邏輯是否有對應的銜接,很幸運地是與上週的waitpid相反,這次的都在musl的REDIR64下有獲得串接。

但是我們發現幾乎所有shared測資都全掛,定睛一看各種 *.ld.err 的紀錄檔發現,會報怨vdso相關的linking會有undefined symbol。
這點是我們此篇的重點之一 — — 目前RISC-V平台上,僅有RV64有VDSO機制可以使用、RV32上游在日前被關掉了。
而riscv_icache_flush這個刷掉instruction cache的syscall,目前在musl的設計上,是直接去叫vdso起來用的。

為了方便,我們可以上一組簡單暴力的patch來硬嚕一次:

diff --git a/src/linux/cache.c b/src/linux/cache.c
index 0eb051c2..0cb65dee 100644
--- a/src/linux/cache.c
+++ b/src/linux/cache.c
@@ -20,6 +20,7 @@ weak_alias(__cachectl, cachectl);
 
 #ifdef SYS_riscv_flush_icache
 
+#if __riscv_xlen == 64
 #define VDSO_FLUSH_ICACHE_SYM "__vdso_flush_icache"
 #define VDSO_FLUSH_ICACHE_VER "LINUX_4.5"
 
@@ -47,4 +48,14 @@ int __riscv_flush_icache(void *start, void *end, unsigned long int flags)
        }
 }
 weak_alias(__riscv_flush_icache, riscv_flush_icache);
+#else // RV64 flush icache
+
+int __riscv_flush_icache(void *start, void *end, unsigned long int flags) 
+{
+               int r = __syscall(SYS_riscv_flush_icache, start, end, flags);
+               if (r != -ENOSYS) return __syscall_ret(r);
+}
+
+weak_alias(__riscv_flush_icache, riscv_flush_icache);
+#endif

在上完這組patch後,我們重跑一次test case,會發現僅剩以下錯誤:

FAIL src/functional/ipc_msg.exe [status 1]
FAIL src/functional/ipc_msg-static.exe [status 1]
FAIL src/functional/ipc_sem.exe [status 1]
FAIL src/functional/ipc_sem-static.exe [status 1]
FAIL src/functional/ipc_shm.exe [status 1]
FAIL src/functional/ipc_shm-static.exe [status 1]
FAIL src/functional/popen.exe [status 1]
FAIL src/functional/popen-static.exe [status 1]
FAIL src/functional/pthread_cancel.exe [timed out]
FAIL src/functional/pthread_cancel-points.exe [timed out]
FAIL src/functional/pthread_cancel-points-static.exe [timed out]
FAIL src/functional/pthread_cancel-static.exe [timed out]
FAIL src/functional/pthread_mutex.exe [signal Segmentation fault]
FAIL src/functional/pthread_mutex_pi.exe [signal Segmentation fault]
FAIL src/functional/pthread_mutex_pi-static.exe [signal Segmentation fault]
FAIL src/functional/pthread_mutex-static.exe [signal Segmentation fault]
FAIL src/functional/pthread_robust.exe [timed out]
FAIL src/functional/pthread_robust-static.exe [timed out]
FAIL src/functional/strptime.exe [status 1]
FAIL src/functional/strptime-static.exe [status 1]
FAIL src/functional/tls_init_dlopen.exe [status 1]
FAIL src/math/fma.exe [status 1]
FAIL src/math/fmaf.exe [status 1]
FAIL src/math/powf.exe [status 1]
FAIL src/regression/pthread_cancel-sem_wait.exe [timed out]
FAIL src/regression/pthread_cancel-sem_wait-static.exe [timed out]
FAIL src/regression/pthread_once-deadlock.exe [status 1]
FAIL src/regression/pthread_once-deadlock-static.exe [timed out]
FAIL src/regression/pthread-robust-detach.exe [status 1]
FAIL src/regression/pthread-robust-detach-static.exe [status 1]
FAIL src/regression/statvfs.exe [status 1]
FAIL src/regression/statvfs-static.exe [status 1]
FAIL src/regression/tls_get_new-dtv.exe [status 1]

其中popen()的測項是因為他試圖呼叫host的echo,但是host的echo是x86-64的檔案,當然沒辦法被qemu-riscv32 (RUN_WRAP)所包圍的環境去運行。
為了先在這個環境底下跑,我們不如就來餵它一個cross-build的busybox吧,這時就是我們之前建置 buildroot 全家桶的原因了:

(1) 首先,請將 buildroot/output/build/busybox-xxx 複製一份出來
(2) 修改 .config 將CC 與 LD 修改為 musl-gcc
(3) 修改CLFAGS,添加 /path/to/buildroot/output/build/linux-headers-5.4.139/usr/include 以便讓 busybox 可以吃Linux kernel header
(4) 建議 make menuconfig 開啟 debug build以及static link以便抓蟲

接下來: CROSS_COMPILE=riscv32-linux- make 便可以獲得一個 staticall linked的busybox
我們快速地把它 cp 一份成echo看看。

然後,回到我們的 libc-test,修改 popen.c 測項的程式碼,將echo指向剛剛的busybox重編重跑。
結果發現他死在 ppclose上,此時發現,又是wait4遺毒。

但是這時,我決定採取截然不同的道路來處理這件事了,wait4的manual page直接明講:

the following wait4() call:

           wait4(pid, wstatus, options, rusage);

       is equivalent to:

           waitpid(pid, wstatus, options);

在上一篇,我們已經將waitpid打好patch了,直接讓wait4串上來吧:

--- a/src/linux/wait4.c
+++ b/src/linux/wait4.c
@@ -8,32 +8,33 @@
 pid_t wait4(pid_t pid, int *status, int options, struct rusage *ru)
 {
        int r;
-#ifdef SYS_wait4_time64
-       if (ru) {
-               long long kru64[18];
-               r = __syscall(SYS_wait4_time64, pid, status, options, kru64);
-               if (!r) {
-                       ru->ru_utime = (struct timeval)
-                               { .tv_sec = kru64[0], .tv_usec = kru64[1] };
-                       ru->ru_stime = (struct timeval)
-                               { .tv_sec = kru64[2], .tv_usec = kru64[3] };
-                       char *slots = (char *)&ru->ru_maxrss;
-                       for (int i=0; i<14; i++)
-                               *(long *)(slots + i*sizeof(long)) = kru64[4+i];
-               }
-               if (SYS_wait4_time64 == SYS_wait4 || r != -ENOSYS)
-                       return __syscall_ret(r);
-       }
-#endif
-       char *dest = ru ? (char *)&ru->ru_maxrss - 4*sizeof(long) : 0;
-       r = __syscall(SYS_wait4, pid, status, options, dest);
-       if (r>0 && ru && sizeof(time_t) > sizeof(long)) {
-               long kru[4];
-               memcpy(kru, dest, 4*sizeof(long));
-               ru->ru_utime = (struct timeval)
-                       { .tv_sec = kru[0], .tv_usec = kru[1] };
-               ru->ru_stime = (struct timeval)
-                       { .tv_sec = kru[2], .tv_usec = kru[3] };
-       }
+    r = waitpid(pid, status, options);

打完這組patch,恭喜~除了解調一個popen的測項,我們那隻busybox shell也可以正常運作了。

事到如今,其實我們的musl libc porting已經有個60分左右,SYSV IPC實際使用的比例不大。
下期預告,我們將會先嘗試看看把 Litex-on-Vexriscv 的 buildroot based filessystem換成這一隻試試看。


上一篇
musl libc 簡介與其 porting(五) Knocking on Heaven's Door
下一篇
LiteX/VexRiscv 簡介與使用 (一) 太初有光
系列文
Port Alpine Linux to open source RISC-V platform30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言