Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/28.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
将linux中运行的汇编代码的结果重定向到文本文件_Linux_Gcc_Assembly_Printf_Io Redirection - Fatal编程技术网

将linux中运行的汇编代码的结果重定向到文本文件

将linux中运行的汇编代码的结果重定向到文本文件,linux,gcc,assembly,printf,io-redirection,Linux,Gcc,Assembly,Printf,Io Redirection,我正试图编写一个Python脚本,以测试我在汇编中编写的各种代码的输出与预期的输出。但是,我很难将输出重定向到文件中。 我写了以下内容: extern printf LINUX equ 80H ; interupt number for entering Linux kernel EXIT equ 1 ; Linux system call 1 i.e. exit () section .data intfmt: db "%ld", 10,

我正试图编写一个Python脚本,以测试我在汇编中编写的各种代码的输出与预期的输出。但是,我很难将输出重定向到文件中。 我写了以下内容:

extern printf
LINUX   equ     80H     ; interupt number for entering Linux kernel
EXIT    equ     1       ; Linux system call 1 i.e. exit ()
section .data
    intfmt: db "%ld", 10, 0

segment .text
    global  main


main:
    push rax
    push rsi
    push rdi
    mov rsi, 10
    mov rdi, intfmt
    xor rax, rax
    call printf
    pop rdi
    pop rsi
    pop rax 
    call os_return      ; return to operating system


os_return:
    mov  rax, EXIT      ; Linux system call 1 i.e. exit ()
    mov  rbx, 0     ; Error code 0 i.e. no errors
    mov rcx, 5
    int  LINUX      ; Interrupt Linux kernel
然后,我在控制台中执行以下操作:

nasm -f elf64 basic.asm
gcc -m64 -o basic basic.o
./basic
输出10到屏幕。 但是如果我进去

./basic > basic.txt
cat basic.txt
basic.txt显示为空文件。 我的总体目标是编写一个shell脚本,在每个程序集文件上循环编译和运行该文件,然后将该脚本的输出重定向到一个文件中。但是,我不能这样做,直到我可以让它与一个单一的文件工作。 我想知道这和我打电话给printf有关吗?尽管我有一种错觉,认为printf会写给STDOUT


提前谢谢

您的重定向是正确的;问题必须在生成的程序集中

调试此类问题的工具是
strace
。在
strace
下运行程序显示:

strace ./basic
...
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa5bb8da000
write(1, "10\n", 3)                     = 3
10
write(1, "z\377n\f\377\177\0\0\0\0\0\0\0\0\0\0\202\377n\f\377\177\0\0\362\377n\f\377\177\0\0"..., 139905561665008 <unfinished ... exit status 0>
这只是syscall的返回。写作成功了吗?(我们知道是的,因为我们在上面看到了它的输出,但让我们确认一下。)

好。写入预期的3个字符

(gdb) c

Catchpoint 1 (call to syscall 'write'), 0x0000000000400577 in os_return ()
这是我们没想到的。从哪里来

(gdb) bt
#0  0x0000000000400577 in os_return ()
#1  0x0000000000400557 in main ()
(gdb) disas
Dump of assembler code for function os_return:
   0x0000000000400557 <+0>: movabs $0x1,%rax
   0x0000000000400561 <+10>:    movabs $0x0,%rbx
   0x000000000040056b <+20>:    movabs $0x5,%rcx
   0x0000000000400575 <+30>:    int    $0x80
=> 0x0000000000400577 <+32>:    nop
   0x0000000000400578 <+33>:    nop
   0x0000000000400579 <+34>:    nop
   0x000000000040057a <+35>:    nop
   0x000000000040057b <+36>:    nop
   0x000000000040057c <+37>:    nop
   0x000000000040057d <+38>:    nop
   0x000000000040057e <+39>:    nop
   0x000000000040057f <+40>:    nop
End of assembler dump.
(gdb) quit
从上面可以看出,
EXIT
在32位模式下应该是1,但在64位模式下应该是60

那你写什么呢?它是64位模式下的1吗

grep 'define .*NR_write' /usr/include/asm/unistd_64.h 
#define __NR_write              1
#define __NR_writev             20
的确如此。因此,我们解决了“迷路文字从何而来”的难题。将
EXIT
固定为60,然后在
strace
下重新运行,我们现在看到:

...
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa5bb8da000
write(1, "10\n", 3)                     = 3
10
_exit(1)                                = ?
这仍然是不对的。我们应该调用
\u出口(0)
,而不是
\u出口(1)
。查看一下
x86_64
,就会发现您的寄存器使用不正确:syscall号码应该在
%rax
中,但是
%rdi
中的参数、
%rsi
%rdx
中,等等

解决了这个问题(并删除了伪的
mov rcx,5
),我们最终从
strace
获得了所需的输出:

...
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa5bb8da000
write(1, "10\n", 3)                     = 3
10
_exit(0)                                = ?
因此,现在我们准备看看上述修复是否也解决了重定向问题

在strace下重新运行,输出重定向:

strace ./basic > t
...
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f08161eb000
_exit(0)                                = ?
显然,我们对
write
的调用丢失了。它去哪里了

默认情况下,
stdout
输出是行缓冲的,当重定向到文件时会得到完全缓冲。也许我们错过了一个
fflush
调用

实际上,在退出之前添加对
fflush(NULL)
的调用可以解决问题:

...
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f8afd450000
write(1, "10\n", 3)                     = 3
_exit(0)                                = ?

我希望你今天学到了一些东西(我做到了;-)

试着从main退出

mov rax, 0; exit code
ret

您正在控制台上正确重定向输入。你检查过程序集是否打印到std out吗?如果你运行
/basic | cat
,你会在屏幕上看到什么?John-/basic | cat仍然不返回任何内容Jex-我查阅了printf文档,它说它打印到stdout。相关:-不要这样做。此外,如果您使用诸如printf之类的stdio函数,请调用
exit(3)
或从main返回,而不是进行原始
\u exit(2)
系统调用,该调用不检查stdio缓冲区是否需要先刷新。这就是重定向失败的原因。不,问题调用的代码使用32位接口退出,在64位模式下运行时会混淆strace。您的答案是假设
strace
正确解码
int 0x80
系统调用的64位代码。它(或者说以前没有;由于内核支持更好,它在过去半年左右终于做到了)。没有杂散的
write()
系统调用,这就是
strace
错误解码
exit
的方式。唯一真正的问题是fflush失败,或者调用exit,或者从main返回。使用int 0x80 ABI通常是个坏主意,但不是问题的直接原因。最终修复的中间步骤实际上引入了新的bug。是的,这是有效的(因为它会导致在退出之前刷新stdio缓冲区),但您的答案应该解释原因。
...
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa5bb8da000
write(1, "10\n", 3)                     = 3
10
_exit(0)                                = ?
strace ./basic > t
...
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f08161eb000
_exit(0)                                = ?
...
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f8afd450000
write(1, "10\n", 3)                     = 3
_exit(0)                                = ?
mov rax, 0; exit code
ret