大会 x86 上的推送/弹出分段错误

Posted

技术标签:

【中文标题】大会 x86 上的推送/弹出分段错误【英文标题】:Push/Pop segmentation fault at Assembly x86 【发布时间】:2014-07-30 08:47:33 【问题描述】:

我正在使用 elf64 来编译我的程序集 x86 代码: 我有这个子程序:

printNumber:
    mov EAX, EDX ; EDX contain some value like "35"
    mov ESI, 10 ; to divide by 10
    MOV ECX,0 ; counter
    whileDiv:
            cmp EAX, 0 
            je endWhileDiv
            xor rdx, rdx ; clean RDX
            idiv ESI ; EAX=EAX/10  and EDX = EAX%10

            push rdx ; this line generate a segmentation fault

            add ECX, 1; count how many items i has added into stack
            jmp whileDiv
    endWhileDiv:
    ret 

我正在尝试使用 push 将数字的所有数字推送到我的堆栈中,但我遇到了分段错误。 当我评论这一行时:

 push rdx ; this line generate a segmentation fault

我不会再犯“Segmentation Fault”

我使用“push rdx”而不是“push EDX”,因为我在 NASM 使用 64 位模式 当我尝试使用:“push EDX”时,出现此错误:“64 位模式不支持指令”

请有人帮忙告诉我为什么会发生这种情况以及如何解决?

PS:对不起我的英语不好

【问题讨论】:

在64位模式下返回地址不是也位于栈顶吗?如果是这样,在你的那个循环之后,它就不会了。 【参考方案1】:

不应该是“PUSH EDX”而不是“PUSH RDX”吗?或者,如果您真的需要推送 64 位,也许可以使用 PUSH dword ptr 0/PUSH EDX 组合?想知道它是否最终会变得不对齐并且不喜欢它?以前的 x86 模式不关心对齐,但也许它适用于 x64 指令?

【讨论】:

我的目标是将 32 位推入堆栈,但是当我尝试使用类似:PUSH EDX 的东西时,我收到此编译错误:“64 位模式不支持指令”。我在 NASM 使用 elf64 为什么在为 64 位模式编写代码时全部使用 32 位寄存器? 因为我使用的是大学计算机并且只能使用 64 位模式,而我使用的所有寄存器都是 32 位的,因为我只需要 32 位。但要推入堆栈,我必须使用 64 位【参考方案2】:

指令

push rdx;

就其本身而言,仅在极少数情况下会导致分段错误:当您的堆栈用完或您弄乱了 (E)SP 时。由于您可以运行该代码,因此我认为您没有执行第二个,如果这是您的应用程序所做的全部,第一个是相当不切实际的。但上面的迈克尔指出了正确的方向:导致分段错误的不是推送指令,而是ret 之前的缺失弹出。在函数结束时,堆栈必须包含与开始时完全相同数量的元素,否则 ret 指令将读取堆栈底部的任何内容并尝试将其用作返回地址 -> bang。

您不能以这种方式使用堆栈返回值。您(例如)需要调用函数为返回数据分配内存并将其地址作为参数提供。阅读有关在汇编语言中调用约定和传递参数的信息。

【讨论】:

【参考方案3】:

我看到了 push rdx,但没有看到 pop rdx。你不断将值压入堆栈,当你到达 RET 时,你会返回到以前 RDX 内容的地址。

【讨论】:

以上是关于大会 x86 上的推送/弹出分段错误的主要内容,如果未能解决你的问题,请参考以下文章

x86 程序集分段错误

当应用程序在后台运行时,iOS 7.x 上的 UINavigationController 推送/弹出错误

分段错误:在 C++ 中弹出向量时出现 11

getaddrinfo() 上的段错误

分段错误与页面错误

获取“分段错误核心转储”