我正在用汇编语言编写,我正在尝试弄清楚如何执行 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 设置为系统调用号 0xb (11) 用于 execve 系统调用。执行时,它返回 /bin/ls
,即我们要求它查找的 ls
的位置。
我如何将 /bin/ls
的结果存储在某处以供其他用途?就像如果我想继续编写代码并将此处返回的内容用作下一段代码的一部分,我该如何将返回值保存在寄存器或堆栈中?
最佳答案
基本上,您必须对此做一些变体:
- 使用
pipe()
系统调用来创建一个 fifo。 fork()
关闭子进程。在父进程中,这将返回您需要记住的子进程 ID。在 child 中,这返回零。- 在父端关闭fifo的写端,在子端关闭读端。
- 在子进程中,使用
dup2()
将管道的写入端移动到文件描述符1。然后关闭管道的原始文件描述符。 - 在 child 中,
execve
您要运行的程序。请注意,execve
用新图像替换了当前进程,因此我不确定您希望以前的程序如何工作。 - 在父级中,从管道读取直到遇到 EOF(即
read()
返回零)。你读到的是 child 的标准输出。将该输出存储在缓冲区中。 - 最后,使用
wait()
收集到 child 的退出状态。如果不这样做,死去的 child 就会像僵尸一样在进程表中徘徊,占用资源。
除了管道,您还可以open()
一个文件来写入输出。这样做的好处是您可以使用 fstat()
找出进程写入了多少输出。但是,您随后需要实现类似于 tmpfile
函数的逻辑来创建和打开临时文件。
关于linux - 在汇编中执行后如何将 execve 系统调用的输出返回到寄存器或堆栈?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44335313/