汇编程序从堆栈中写入字符
Posted
技术标签:
【中文标题】汇编程序从堆栈中写入字符【英文标题】:Assembly program to write character from stack 【发布时间】:2018-01-18 17:21:41 【问题描述】:我正在尝试在 AT&T 语法汇编中编写一个测试程序,将某些字符的 ascii 值推送到堆栈,然后打印它们。我的代码如下:
.text
.global main
main:
push $0
push $10
push $65
mov $4,%eax
mov $1,%ebx
mov %esp,%ecx
mov $3,%edx
int $0x80
mov $1,%eax
int $0x80
我希望这个程序做的是将 0、10 和 65 压入堆栈,使堆栈为 65、10、0(大写字母 A、换行符、字符串结尾)。将eax
和ebx
设置为写入标准输出的值,并将ecx
设置为堆栈指针,以便它写入堆栈上的内容,而edx
是堆栈上的长度(即3) .当我运行它时,绝对没有任何反应。你能帮我理解我做错了什么以及这里实际发生了什么吗?
【问题讨论】:
push
将 4 个字节存储到内存中(在 32 位模式下)。因此,您应该只看到您的信 A
。单个push $0x0a41
也应该为您提供换行符。请注意,write()
或您的终端并不特别关心终止零,因此只需打印两个字节就足够了。
使用我的初始代码,或者使用您建议的单推版本,控制台不会打印任何内容。
两者都按照描述在这里工作。然后通过strace
运行您的代码。
在调试器中运行,在每个push
之后检查rsp/esp
的值,提出质疑。如果它移动了8
,您正在将这个 32b linux API 汇编源编译为 64b 二进制文件,这将不起作用,您需要使用syscall
而不是int 0x80
,并修复参数(syscall
服务是不同的)。如果您没有调试器,只需尝试添加mov rax,rcx
,这在 32b 模式下应该会失败,但会在 64b 模式下编译)。你绝对需要调试器,并学会使用它。
如果您不小心将其编译为 64b 二进制文件:请检查此答案,为什么它不起作用:***.com/q/46087730/4271923
【参考方案1】:
每条push
指令将 4 个字节压入堆栈。所以,这就是int 0x80
之前堆栈的样子:
....
---------- (highest address)
| 0x00 |
----------
| 0x00 |
----------
| 0x00 |
----------
| 0x00 |
---------- <-- push $0
| 0x00 |
----------
| 0x00 |
----------
| 0x00 |
----------
| 0x0A |
---------- <-- push $10
| 0x00 |
----------
| 0x00 |
----------
| 0x00 |
----------
| 0x41 |
---------- <-- push $65 <-- ESP
但是,此时您希望堆栈看起来像:
....
----------
| 0x00 |
----------
| 0x0A |
----------
| 0x41 |
---------- <-- ESP
这可以通过将您的 push
指令替换为以下内容来实现:
push $0x0a41
即:
.text
.global main
main:
push $0x0a41
mov $4,%eax ;system call write()
mov $1,%ebx ;file descriptor (stdout)
mov %esp,%ecx ;string
mov $3,%edx ;length of the string
int $0x80
mov $1,%eax
int $0x80
在edx
寄存器中你已经指定了字符串的长度(即:3
),NUL 字符是没有意义的(你实际上是把它发送到stdout
)。
【讨论】:
使用该 push 语句并将edx
设置为 3 也不会打印任何内容。
如果您使用的是 64 位系统,则需要汇编和链接为 32 位代码才能正常工作。
正确:使用gcc -m32
。以上是关于汇编程序从堆栈中写入字符的主要内容,如果未能解决你的问题,请参考以下文章
yongc语言编写单片机程序,出现了堆栈溢出情况,怎么解决?堆栈指针怎么初始化?
程序一 用记事本建立文件src.dat,其中存放若干字符。编写程序,从文件src.dat中读取数据,统计其中的大写字母小写字母数字其它字符的个数,并将这些数据写入到文件test.dat中。