i386平台GNU/Hurd无glibc的Hello World汇编程序实现
i386架构GNU Hurd无glibc依赖Hello World汇编实现
问题说明
- 实现目标:编写i386架构下运行于GNU Hurd系统的Hello World汇编程序,直接调用GNU Hurd(Mach)原生系统调用/RPC,不依赖glibc,完成向标准输出打印固定字符串后正常退出的功能。
- 等价表述:通过可端到端运行的精简汇编示例,演示GNU Hurd(Mach)平台下glibc对POSIX标准函数write与*_exit*的底层实现逻辑。
对照参考:i386架构Linux平台实现
Linux下通过int $0x80软中断触发系统调用,参数通过寄存器传递,实现代码如下:
/* File hello.s */ .global _start .text _start: mov $4, %eax /* __NR_write == 4. */ mov $1, %ebx /* STDOUT_FILENO == 1. */ mov $msg, %ecx /* Pointer to message. */ mov $msg_end-msg, %edx /* Message size in bytes. */ int $0x80 /* System call. */ mov $1, %eax /* __NR_exit == 1. */ xor %ebx, %ebx /* EXIT_SUCCESS == 0. */ int $0x80 /* System call. */ msg: .ascii "Hello, World!\n" msg_end:
编译命令(兼容版GNU Binutils)
$ as --32 -march=i386 -o hello.o hello.s $ ld -m elf_i386 -o hello hello.o
运行效果
$ ./hello Hello, World!
i386架构GNU Hurd平台实现
和Linux宏内核直接暴露系统调用号、寄存器传参的模式不同,GNU Hurd基于Mach微内核设计,IO操作通过向对应服务端口发送RPC实现,进程控制可直接调用Mach微内核原生陷阱。以下代码完全不依赖glibc,直接通过Mach陷阱与RPC实现功能:
/* File hello.s, i386 GNU Hurd, no glibc dependency */ .global _start .text _start: /* 1. 遍历启动栈,找到文件描述符表 */ movl 4(%esp), %eax /* 跳过argc,指向argv数组起始位置 */ skip_argv: addl $4, %esp movl (%esp), %ecx testl %ecx, %ecx jnz skip_argv /* 遍历到argv数组结尾的NULL */ skip_envp: addl $4, %esp movl (%esp), %ecx testl %ecx, %ecx jnz skip_envp /* 遍历到envp数组结尾的NULL */ /* 2. 取出stdout(fd=1)对应的Mach IO端口 */ movl 12(%esp), %ebx /* 启动数据块偏移12位为文件描述符端口数组基址 */ movl 4(%ebx), %ebx /* 数组偏移4字节对应fd=1(标准输出)的端口 */ /* 3. 调用io_write RPC实现POSIX write(1, msg, len) */ movl $16002, %eax /* io_write RPC调用号(io接口基号16000 + write例程偏移2) */ pushl $0 /* 最后一个参数:写入长度输出指针,传NULL忽略 */ pushl $(msg_end - msg) /* 参数:待写入字符串长度 */ pushl $msg /* 参数:待写入字符串内存地址 */ pushl %ebx /* 参数:目标IO端口(stdout) */ pushl %eax /* 压入RPC调用号 */ int $0x80 /* 触发Mach软中断 */ addl $20, %esp /* 清理栈上的调用参数 */ /* 4. 调用Mach原生陷阱实现退出 */ movl $-28, %eax /* SYS_task_self 陷阱号,获取当前进程的task端口 */ int $0x80 movl %eax, %ebx movl $-10, %eax /* SYS_task_terminate 陷阱号,终止当前task */ pushl %ebx /* 传入当前task端口作为参数 */ int $0x80 msg: .ascii "Hello, World!\n" msg_end:
编译命令(i386 GNU Hurd环境下,使用GNU Binutils)
$ as --32 -march=i386 -o hello.o hello.s $ ld -m elf_i386 -o hello hello.o
运行效果
$ ./hello Hello, World!
实现说明
- POSIX
write的底层逻辑:glibc在Hurd平台下封装write时,会先从进程文件描述符表取出对应fd绑定的服务端口,再组装参数发起io_writeRPC请求,和上述汇编逻辑完全一致。 - POSIX
_exit的底层逻辑:常规_exit会向proc服务端口发起proc_exitRPC通知进程服务器做资源回收,上述示例直接调用Mach内核的task_terminate陷阱实现硬退出,效果等价。
内容的提问来源于stack exchange,提问作者pts
相关产品推荐
相关产品推荐

