0

我正在尝试学习一些非常基本的 ASM,以帮助我阅读 gdb 输出找出东西。我一直在网上关注一些教程,并且遇到了一些我不知道该怎么做的事情。

我正在关注的教程(http://programminggroundup.blogspot.fr/2007/01/programming-from-ground-up.html)在第 5 章中讨论了字符串 IO。它使用 .bss 段来声明 500 长度输入的数组。我可以让它工作没有问题。但是,我现在试图将数组放在堆栈上,而不是放在 .bss 段中(这对我来说似乎是“全局内存”)。

问题是,我无法弄清楚我做错了什么。据我在这里看到的,我已经在堆栈上移动了一个 64 字节的部分,我试图用它来保存输入,然后输出它。该代码没有核心或以其他方式展开,但是当我运行它并键入“Hello”(不带引号)时,结果是“ello”,写在下一个命令行中。它后面是一个换行符,因此在程序终止时立即执行“hello”。

user_omitted@serveromitted:~/folderomitted>./basic_io
Hello
user_omitted@serveromitted:~/folderomitted>ello

据我在这里看到的,我正在写入堆栈。我希望我不需要将其归零,因为输入应该正确覆盖内容。我在这里做错了什么?

这是使用带有气体的 unix IA-64 系统。此外,如果我正在做一些非常愚蠢的事情(不仅仅是与我遇到的问题有关),请告诉我!

.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
4

1 回答 1

1

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.

于 2013-08-02T14:34:30.163 回答