![](/img/trans.png)
[英]Why does calling 'pop' in this piece of assembly code cause a segmentation fault?
[英]Why does this AT&T assembly code give a segmentation fault?
这是我的第一个汇编源代码,我想使用scanf
函数,但是此ELF给出了分段错误。
因此,我尝试解决使用核心转储的问题,但我做不到。
.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函数。
printf
或scanf
也可能会崩溃,因为当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.