我遇到了gdb
的问题,我在Debian Linux(Jessie / Testing)中无法弄清楚。在尝试调试汇编程序时,我无法让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
然后我像这样运行gdb:
gdb foo
(gdb) r <test.in 1>test1.out
当我在安装了gdb 7.6.2的Debian Jessie笔记本电脑上运行时,会出现段错误。但是,当我在Debian Linux服务器上运行它(运行sid,相同的gdb
版本)时,代码会执行它应该执行的操作。我已经把它打开了,但我很好奇为什么它会在我的笔记本电脑上出现段错误。有什么想法吗?
答案 0 :(得分:1)
我通常不会回答我自己的问题,但我弄清楚为什么它不起作用。当使用64位操作系统时,as和ld应该知道您何时尝试编译和链接32位文件。出于某种原因,这在过去运作得很好。然而,通过这个程序,它没有(我想我过去只是幸运)。无论如何,修改上述命令:
as --32 -gstabs foo.s -o foo.o
ld -m elf_i386 foo.o -o -foo
是程序正常运行所必需的。特别是当我尝试将64位操作系统下的汇编代码编译并链接到32位可执行文件时。
答案 1 :(得分:0)
您使用pushw
/ popw
错误对齐堆栈指针,这样做是个坏主意。我的猜测是你的笔记本电脑上的某些组件(可能是系统调用时的内核本身)并不是那样并导致错误。
顺便说一句,代码在gdb
以外的笔记本电脑上运行良好吗?
答案 2 :(得分:0)
首先,代码中没有注释,也没有关于程序应该做什么的解释,这不是提问的好方法。但是,因为您在这里相对较新,我会通过发布您的代码的评论版来帮助您:
.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
所以代码似乎试图做的是从输入复制到输出。问题出在我所评论的“危险递归”中。&#34;当代码首先从start
开始时,它会推送子程序的返回地址,该子程序是endit
的32位地址。然后在readme
的顶部推送一个16位值为0.渲染为16位值,堆栈如下所示:
+-----------+
| 0 |
+-----------+
| endit-hi |
+-----------+
| endit-lo |
+-----------+
如果sys_read调用返回的值不是零(每次成功读取一个字符时都会返回),我们会递归调用readme
。堆栈现在看起来像这样:
+-----------+
| write2-hi |
+-----------+
| write2-lo |
+-----------+
| 0 |
+-----------+
| endit-hi |
+-----------+
| endit-lo |
+-----------+
然后我们再推一个0字,得到这个:
+-----------+
| 0 |
+-----------+
| write2-hi |
+-----------+
| write2-lo |
+-----------+
| 0 |
+-----------+
| endit-hi |
+-----------+
| endit-lo |
+-----------+
基本上,每次从stdin
读取一个字符时,它将替换堆栈中的最新0
,但会很快烧掉大量的堆栈空间 - 每个输入字符有三个16位字。如果读取大文件,这很可能导致堆栈崩溃。