使用asm的基于堆栈的字符串IO - 我做错了什么?

时间:2013-08-02 11:23:03

标签: unix assembly gas

我正在尝试学习一些非常基本的ASM,以帮助我阅读gdb输出找出东西。我一直在线学习一些教程,并且遇到了一些我无法弄清楚如何做的事情。

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

问题是,我无法弄清楚我做错了什么。据我所知,我在堆栈上移动了一个64字节的部分,我试图用它来保存输入,然后输出它。代码没有核心或以其他方式表示,但是当我运行它并输入“Hello”(没有引号)时,结果是“ello”,写在下一个命令行中。接下来是行返回,因此“ello”会在程序终止时立即执行。

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

1 个答案:

答案 0 :(得分:1)

这看起来像是同一个问题:

Linux write sys call using string on stack

免责声明:我正在运行32位硬件,没有使用64位代码的经验。对于64位代码,使用32位引用(Jon Bartlett的优秀PGU!)“可能”是错误的。如上面的链接(和右侧)所示,您使用的是32位系统调用号,将参数放在适合32位代码的寄存器中,并使用32位int 0x80。我被告知这是有效的(仍然),你确认它适用于.bss中的缓冲区。我认为%rsp“太高”,如链接所示。

在任何情况下,sys_read都不会返回以零结尾的字符串,sys_write如果有,则不会注意它。 sys_write写入%edx%rdx)中的字节数,无论它是否为“垃圾”。 sys_read返回%eax%rax)中实际输入的字节数,这是您要放入%edx%rdx)的内容(同一个寄存器)对于sys_write,对于这种情况下的32位或64位代码)。这不是你的问题,但它仍然是“错误的”。

如果讨厌的用户在32位代码中输入的%edx允许的次数超过允许的话,我会在命令提示符下看到“过剩”这个问题。这可能是“危险的”!如有必要,“冲洗缓冲区”可能是个好主意。如果%eax%rax)小于%edx%rdx),那么您没问题。如果它们相等,请检查缓冲区中的最后一个字节是否有换行符(ascii代码0xa)。如果它在那里,你没事。如果没有,请继续阅读,直至找到换行符。对于您是唯一用户的玩具程序来说,这可能是“过度杀伤”,但了解这个问题仍然是一个好主意。