Linux gdb不接受输入重定向
我在Debian Linux(Jessie/Testing)中无法完全理解Linux gdb不接受输入重定向,linux,assembly,x86,gdb,debian,Linux,Assembly,X86,Gdb,Debian,我在Debian Linux(Jessie/Testing)中无法完全理解gdb的问题。当试图调试汇编程序时,我无法让gdb接受输入重定向。以下是我试图调试的代码: #The program reverses the input given to it. For example "123456789" will #become "987654321" .global _start readme: pushw $0 #allocate 2 bytes onto t
gdb
的问题。当试图调试汇编程序时,我无法让gdb
接受输入重定向。以下是我试图调试的代码:
#The program reverses the input given to it. For example "123456789" will
#become "987654321"
.global _start
readme:
pushw $0 #allocate 2 bytes onto the stack
movl $3,%eax #system call for read
movl $0,%ebx #stdin
movl %esp,%ecx #read to stack pointer
movl $1,%edx #number of bytes to read
int $0x80 #execute instruction
cmpl $0,%eax #check number of bytes read
jz returnme #jump to label 'returnme' if zero bytes are read
writeme:
call readme #recursive call to continue to next character
movl $4,%eax #system call for write
movl $1,%ebx #stdout
movl %esp,%ecx #write what is in the stack pointer
movl $1,%edx #write one byte
int $0x80 #execute instruction
returnme:
popw %ax #clean up
ret #return to line after previous call
_start:
call readme #call subroutine readme
endit:
movl $1,%eax #These lines are for exiting the program
movl $0,%ebx
int $0x80
我使用以下命令编译它:
as -gstabs -o foo.o foo.s
ld -o foo foo.o
as --32 -gstabs foo.s -o foo.o
ld -m elf_i386 foo.o -o -foo
然后我像这样运行gdb:
gdb foo
(gdb) r <test.in 1>test1.out
+-----------+
| 0 |
+-----------+
| endit-hi |
+-----------+
| endit-lo |
+-----------+
+-----------+
| write2-hi |
+-----------+
| write2-lo |
+-----------+
| 0 |
+-----------+
| endit-hi |
+-----------+
| endit-lo |
+-----------+
gdbfoo
(gdb)r test1.out
当我在安装了GDB7.6.2的Debian Jessie笔记本电脑上运行这个程序时,它会出现故障。但是,当我在DebianLinux服务器上运行此代码时(运行sid,same
gdb
version),代码会执行它应该执行的操作。我已经把它交上来了,但我很好奇为什么我的笔记本电脑会出故障。有什么想法吗?您使用的pushw
/popw
使堆栈指针错位,这样做不好。我的猜测是,您笔记本电脑上的某些组件(可能是系统调用时的内核本身)不喜欢这样,并导致了故障
顺便问一下,在你的笔记本电脑上,代码在gdb之外运行正常吗?首先,在代码中没有注释,也没有解释程序应该做什么,这不是一个好的提问方式。但是,由于您在这里相对较新,我将通过发布代码的注释版本来帮助您:
.global _start
readme:
pushw $0
movl $3,%eax ; sys_read
movl $0,%ebx ; file = stdin
movl %esp,%ecx ; pointer to userbuff
movl $1,%edx ; count = 1
int $0x80 ; do it
cmpl $0,%eax ; check return value
jz returnme ; if it's zero, return
writeme:
call readme ; dangerous recursion!
write2:
movl $4,%eax ; sys_write
movl $1,%ebx ; file = stdout
movl %esp,%ecx ; pointer to userbuff = stack?!
movl $1,%edx ; 1 byte
int $0x80 ; do it
returnme:
popw %ax ; clean up stack
ret ; return
_start:
call readme
endit:
movl $1,%eax ; sys_exit
movl $0,%ebx ; error code = 0 (OK)
int $0x80 ; do it
因此,代码似乎试图做的是从输入复制到输出。问题出在我评论为“危险递归”的那一行中。当代码第一次从start
开始时,它推送子程序的返回地址,即endit
的32位地址。然后在readme
的顶部推送16位值0。渲染为16位值时,堆栈如下所示:
gdb foo
(gdb) r <test.in 1>test1.out
+-----------+
| 0 |
+-----------+
| endit-hi |
+-----------+
| endit-lo |
+-----------+
+-----------+
| write2-hi |
+-----------+
| write2-lo |
+-----------+
| 0 |
+-----------+
| endit-hi |
+-----------+
| endit-lo |
+-----------+
如果sys_read调用返回的不是零(它每次成功读取字符时都会返回零),那么我们将递归调用readme
。堆栈现在如下所示:
gdb foo
(gdb) r <test.in 1>test1.out
+-----------+
| 0 |
+-----------+
| endit-hi |
+-----------+
| endit-lo |
+-----------+
+-----------+
| write2-hi |
+-----------+
| write2-lo |
+-----------+
| 0 |
+-----------+
| endit-hi |
+-----------+
| endit-lo |
+-----------+
然后我们再按一个0字,得到如下结果:
+-----------+
| 0 |
+-----------+
| write2-hi |
+-----------+
| write2-lo |
+-----------+
| 0 |
+-----------+
| endit-hi |
+-----------+
| endit-lo |
+-----------+
基本上,每次从
stdin
读取字符时,它都会替换堆栈上最新的0
,但会很快消耗大量堆栈空间-每个输入字符三个16位字。如果读取大文件,这很可能会导致堆栈崩溃。我通常不会回答自己的问题,但我找到了它不起作用的原因。当使用64位操作系统时,as和ld应该知道您何时尝试编译和链接32位文件。出于某种原因,这在过去一直运作良好。然而,有了这个项目,情况却并非如此(我认为我过去只是幸运而已)。无论如何,对上述命令的更正如下:
as -gstabs -o foo.o foo.s
ld -o foo foo.o
as --32 -gstabs foo.s -o foo.o
ld -m elf_i386 foo.o -o -foo
是程序正常工作所必需的。特别是当我试图编译64位操作系统下的汇编代码并将其链接到32位可执行文件时。我认为这是因为我使用的是pushw而不是pushl(popw也是如此)?代码根本不在gdb之外运行。我想我知道了为什么(或者至少在我的系统上为什么)它不工作了。试图在64位操作系统上编译32位程序集无效。我在代码中添加了注释。很抱歉,我完全忘记了告诉代码的作用和注释。我太专注于问题本身了。现在有了这个项目的实际目的,也许更容易理解我为什么这样做。