32位Linux内核下init进程调用syscall被终止的解决方法
问题排查与解决
核心错误分析
你的代码主要问题出在系统调用的汇编实现上,导致内核无法正确处理调用,进而终止init进程:
- 系统调用号赋值错误:汇编第一行
mov %0, %%eax逻辑错误,%0对应未初始化的输出变量ret,正确做法是将系统调用号nr(对应%1)放入%eax。 - 寄存器约束遗漏:代码修改了
%ebp寄存器,但未在clobber列表中声明,编译器无法感知该寄存器被修改,会引发寄存器状态混乱。
修正后的代码
start.S(可保留,补充halt避免意外返回崩溃)
.globl _start .text _start: call main hlt
修正后的init.c
int syscall(int nr, void *a0, void *a1, void *a2, void *a3, void *a4, void *a5) { int ret; __asm__ __volatile__ ( "mov %1, %%eax\n\t" // 正确将系统调用号传入eax "mov %2, %%ebx\n\t" "mov %3, %%ecx\n\t" "mov %4, %%edx\n\t" "mov %5, %%esi\n\t" "mov %6, %%edi\n\t" "mov %7, %%ebp\n\t" "int $0x80\n\t" "mov %%eax, %0\n\t" : "g"(ret) : "g"(nr), "g"(a0), "g"(a1), "g"(a2), "g"(a3), "g"(a4), "g"(a5) : "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi", "%ebp"); // 添加ebp到被修改寄存器列表 return ret; } int main(void) { // write系统调用(0x4)参数:fd=1,buf="Hello",count=5 syscall(0x4, (void*)1, "Hello", (void*)5, 0, 0, 0); while(1) {} return 0; }
额外注意事项
- 编译链接参数:必须用32位目标编译,例如
gcc -m32 -nostdlib start.S init.c -o /bin/init,避免64位编译的兼容性问题。 - 内核启动配置:确认内核启动时指定了正确的init路径,且根文件系统挂载正常,保证
/bin/init可被正确加载。 - 系统调用匹配:32位Linux内核的系统调用号需与内核实现对应,
0x4确实是write调用,但需确保内核已实现该系统调用。
内容的提问来源于stack exchange,提问作者CoderGodToRun
相关产品推荐
相关产品推荐

