Reputation: 478
I am trying to learn some very basic ASM, in order to help me with reading gdb output figuring out stuff. I have been following a few tutorials online, and have come across something I can't figure out how to do.
The tutorial I am following (http://programminggroundup.blogspot.fr/2007/01/programming-from-ground-up.html) talks about string IO in chapter 5. It uses the .bss segment to declare a 500-length array for the input. I can get this to work no problem. However, I'm now trying to have the array on the stack, rather than in the .bss segment (which seems like 'global memory' to me).
The problem is, I can't figure out what I'm doing wrong. As far as I can see here, I have moved a 64-byte section on the stack that I am trying to use to hold the input, and then output it. The code doesn't core or otherwise expode, but when I run it and type "Hello" (without quotes) then the result is "ello", written in the next command-line. It is followed by a return-of-line, thus the 'ello' is immediately executed upon termination of the program.
user_omitted@serveromitted:~/folderomitted>./basic_io
Hello
user_omitted@serveromitted:~/folderomitted>ello
As far as I can see here, I'm writing to the stack. I would expect that I don't need to zero it, as the input should overwrite the content correctly. Am I doing something insanely wrong here?
This is using a unix IA-64 system with gas. Additionally, if I am doing stuff that's really dumb (not just related to the issue I have), please tell me!
.section .text
.globl _start
_start:
pushq %rbp # Store the original base pointer on the stack
mov %rsp, %rbp # The new base pointer is targeting the start of the stack
sub $64, %rsp # Move the stack pointer down by 64 bytes, thus saying we have 64 bytes to play with
mov %rsp, %rcx # Pass the content of the stack pointer to rcx, for the system call
mov $64, %rdx # Store the length of the buffer
mov $3, %rax # State that we want to use system_read
mov $0, %rbx # Select the handler (STDIN)
int $0x80 # invoke
mov $4, %rax # system_write
mov $1, %rbx # STDOUT
mov $64, %rdx # length of buffer
mov %rsp, %rcx # location of the buffer on the stack
int $0x80 # invoke
mov %rbp, %rsp # Restore the stack pointer to the original location
popq %rbp # pop the base pointer off the stack
mov $1, %rax # sys_exit
mov $0, %rbx # return code
int $0x80 # invoke
Upvotes: 0
Views: 97
Reputation: 3119
This looks like the same issue:
Linux write sys call using string on stack
Disclaimer: I am running 32-bit hardware and have no experience with 64-bit code. It "might" be a mistake to use a 32-bit reference (Jon Bartlett's excellent PGU!) for 64-bit code. As indicated in the link above (and on the right), you're using 32-bit system call numbers, putting the parameters in registers suitable for 32-bit code, and using the 32-bit int 0x80
. I'm told that this works (still), and you confirm that it works with buffer in .bss
. I think that %rsp
is "too high", as indicated in the link.
In any case, sys_read
does not return a zero-terminated string, and sys_write
wouldn't pay any attention to it if it did. sys_write
writes the number of bytes in %edx
(%rdx
) regardless of whether it's "garbage" or not. sys_read
returns the number of bytes actually entered in %eax
(%rax
), and this is what you want to put in %edx
(%rdx
) (same register for 32- or 64-bit code in this case) for the sys_write
. This is not your problem, but it's still "wrong".
I've seen this issue of "excess" appearing at the command prompt if the pesky user types more than is allowed in %edx
in 32-bit code. It is potentially "dangerous"! It is probably a good idea to "flush the buffer" if necessary. If %eax
(%rax
) is less than %edx
(%rdx
), you're okay. If they're equal, check the last byte in the buffer for the linefeed (ascii code 0xa). If it's there, you're okay. If not, keep reading until you find the linefeed. This is probably "overkill" for a toy program where you're the only user, but it's still a good idea to be aware of the issue.
Upvotes: 1