Reputation: 111
I have an issue with gdb
that I cannot quite figure out in Debian Linux (Jessie/Testing). When attempting to debug an assembly program, I cannot get gdb
to accept input redirection. Here is the code I am attempting to debug:
#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
I compile it using these commands:
as -gstabs -o foo.o foo.s
ld -o foo foo.o
Then I run gdb like this:
gdb foo
(gdb) r <test.in 1>test1.out
When I run this on my laptop running Debian Jessie with gdb 7.6.2 installed, it segfaults. However, when I run this on a Debian Linux server (running sid, same gdb
version), the code does what it is supposed to. I have already turned this in, but I am curious as to why it segfaults on my laptop. Any ideas?
Upvotes: 0
Views: 122
Reputation: 111
I would not normally answer my own question, but I figured out why it wasn't working. When using a 64-bit operating system, as and ld are supposed to know when you are attempting to compile and link a 32-bit file. For some reason, this had worked just fine in the past. However, with this program, it did not (I would assume I was just lucky in the past). Anyway, a correction to the above commands:
as --32 -gstabs foo.s -o foo.o
ld -m elf_i386 foo.o -o -foo
was required for the program to work correctly. This is specifically when I was attempting to compile and link assembly code under a 64-bit OS into a 32-bit executable.
Upvotes: 1
Reputation: 7090
First, having no comments in the code and no explanation as to what the program is supposed to do is not a good way to ask a question. Because you're relatively new here, though, I'll help you out by posting a commented version of your code:
.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
So what the code appears to be attempting to do is copy from input to output. The problem is in the line that I've commented as "dangerous recursion." When the code first starts at start
, it pushes the return address for the subroutine which is the 32-bit address of endit
. Then at the top of readme
you push a 16-bit value of 0. Rendered as 16-bit values, the stack looks like this:
+-----------+
| 0 |
+-----------+
| endit-hi |
+-----------+
| endit-lo |
+-----------+
If the sys_read call returns something other than zero (which it does every time it successfully reads a character), we then call readme
recursively. The stack now looks like this:
+-----------+
| write2-hi |
+-----------+
| write2-lo |
+-----------+
| 0 |
+-----------+
| endit-hi |
+-----------+
| endit-lo |
+-----------+
Then we push a 0 word again and get this:
+-----------+
| 0 |
+-----------+
| write2-hi |
+-----------+
| write2-lo |
+-----------+
| 0 |
+-----------+
| endit-hi |
+-----------+
| endit-lo |
+-----------+
Basically, each time a character is read from stdin
it will replace the latest 0
on the stack, but will very quickly burn up lots of stack space - three 16-bit words per input character. This is very likely to cause a stack crash if a large file is read.
Upvotes: 0
Reputation: 58762
Your use of pushw
/popw
misaligns the stack pointer, it's a bad idea to do that. My guess is that some component on your laptop (maybe the kernel itself at the time of a system call) doesn't like that and causes the fault.
By the way, does the code run fine on your laptop outside of gdb
?
Upvotes: 0