我正在用汇编语言编写,我试图找出如何执行 execve 系统调用,但我不想将输出打印到终端,而是想知道它的存储位置,以便稍后使用它,谢谢类似管道命令。
例如,这里是通过 execve 执行命令“which”的程序集,本质上是执行命令“$which ls”:
GLOBAL _start
SECTION .TEXT
_start:
XOR EAX,EAX
PUSH EAX
PUSH 0x68636968
PUSH 0x772f6e69
PUSH 0x622f7273
PUSH 0x752f2f2f
MOV EBX, ESP
PUSH EAX
PUSH 0x736c
MOV ESI, ESP
XOR EDX, EDX
PUSH EDX
PUSH ESI
PUSH EBX
MOV ECX, ESP
MOV AL, 0x0B; EXECVE SYSCALL NUMBER
INT 0x80
第 7-10 行将
/usr/bin/which
的地址压入堆栈,第 13 行将参数 ls
压入堆栈。然后,它将参数数组压入堆栈并将其存储在 ECX 中,使 EBX 指向 /usr/bin/which
位置的地址,并将 EAX 设置为 execve 系统调用的系统调用号 0xb (11)。执行时,它返回 /bin/ls
,即我们要求它查找的 ls
的位置。
如何将
/bin/ls
的结果存储在某处以供其他用途?就像如果我想继续编写代码并使用此处返回的内容作为下一段代码的一部分,如何将返回的值保留在寄存器或堆栈中?
基本上,你必须做一些变化:
pipe()
系统调用来创建 fifo。fork()
关闭子进程。在父进程中,这将返回您需要记住的子进程 ID。在孩子中,这返回零。dup2()
将管道的写入端移动到文件描述符1。然后关闭管道的原始文件描述符。execve
您要运行的程序。请注意,execve
用新图像替换了当前进程,所以我不确定您期望以前的程序如何工作。read()
返回零)。你读到的就是孩子的标准输出。将该输出存储在缓冲区中。wait()
收集孩子的退出状态。如果不这样做,死去的孩子就会像僵尸一样徘徊在进程表中,占用资源。除了管道之外,您还可以
open()
将输出写入到文件中。这样做的好处是您可以使用 fstat()
来找出进程写入了多少输出。但是,您随后需要实现类似于 tmpfile
函数的逻辑来创建并打开临时文件。
我和约书亚·坎贝尔有同样的问题。
这里是一个用 nasm 编写的源代码示例的链接,它将使用 pipeline() 创建从父进程到子进程的管道并运行外部命令 (
/bin/echo 'Hello World'
),将结果复制到缓冲区中[tmp] 并随后显示/打印结果:
https://gitlab.com/pagaco/nasm-examples-pipe-linux-64bit/-/blob/main/pipe3/pipe3.asm
程序的具体顺序可以在源代码中找到。 此源代码示例适用于 64 位 Linux 操作系统。
也许这对你有帮助。
致以诚挚的问候。