繁体   English   中英

为什么此AT&T汇编代码会给出分段错误?

[英]Why does this AT&T assembly code give a segmentation fault?

这是我的第一个汇编源代码,我想使用scanf函数,但是此ELF给出了分段错误。

因此,我尝试解决使用核心转储的问题,但我做不到。

使用scanf函数

.section .data

string: 
.ascii "input yournumber : \0"

value: 
.ascii "your value is %d \n\0"

scanf:
.ascii "%d"

.section .text

.globl _start

_start:

movl %esp, %ebp
subl $4, %esp

pushl $string
call printf

leal -4(%ebp), %ebx
pushl %ebx
pushl $scanf
call scanf

pushl -4(%ebp)
pushl $value
call printf

pushl $0
call exit

不仅要查看核心转储,还可以通过启动gdb内的可执行文件来查看如何到达核心转储。 si单步指令。 有关更多GDB提示,请参见https://stackoverflow.com/tags/x86/info的底部。

您有大量可能导致崩溃的错误,有些肯定会崩溃。


您定义了scanf符号,因此call scanf跳到那里。

它在.data部分中,因此该页面可能无法执行。

或给定这些寄存器值的"%d"字节解码为崩溃的x86机器代码。

对于scanf格式字符串,请使用其他符号名称,例如scanf_fmt 同样不要忘记使用.asciz将隐式长度的C字符串零终止。


如果您静态链接了此链接,或者您在MinGW或Cygwin上尝试了此链接,则不会初始化libc,因为您定义的是_start而不是main 在动态链接的Linux可执行文件中,glibc使用动态链接器钩子来调用其init函数。 即使这样, 也不建议从_start使用libc函数。


printfscanf也可能会崩溃,因为当ABI允许它假定为16时,堆栈仅按8字节对齐。在_start入口处,堆栈按16对齐。但是您只执行1 push + 1x sub $4, %esp在printf之前。

但是大多数Linux发行版都不使用-msse2构建32位代码,因此编译器不会使用需要16字节对齐方式的加载/存储来复制内容。 (x86-64 glibc的scanf会在未对齐的堆栈中调用时崩溃。)

实际上,您确实使用对齐的堆栈调用scanf 从入口到_start的总偏移量为16,因为您不会浪费printf返回之后清理堆栈的指令。 只要您知道自己正在这样做,那是一个有效的选择。 (它值得评论,和/或您可以使用mov而不是push来供以后的arg重新使用那些相同的堆栈插槽。)

我建议您查看(优化的)编译器输出,以实现所需功能。 例如在https://godbolt.org/

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM