x86 段错误在"call"运行



我正在研究一个玩具编译器。 我曾经使用 malloc 分配所有内存,但由于我从不调用 free,我认为在堆栈上分配大约 GB 左右然后慢慢使用该缓冲区就足够了(而且更快)。

但。。。现在我正在发生任何有趣的事情之前进行分段错误。 它发生在我大约 30% 的测试用例上(本节中的所有测试用例都相同)。 从 GDB 粘贴:

(gdb) disas
Dump of assembler code for function main:
0x0000000000400bf1 <+0>:    push   rbp
0x0000000000400bf2 <+1>:    mov    rbp,rsp
0x0000000000400bf5 <+4>:    mov    QWORD PTR [rip+0x2014a4],rsp        # 0x6020a0
0x0000000000400bfc <+11>:    sub    rsp,0x7735940
0x0000000000400c03 <+18>:    sub    rsp,0x7735940
0x0000000000400c0a <+25>:    sub    rsp,0x7735940
0x0000000000400c11 <+32>:    sub    rsp,0x7735940
=> 0x0000000000400c18 <+39>:    call   0x400fec <new_Main>
0x0000000000400c1d <+44>:    mov    r15,rax
0x0000000000400c20 <+47>:    mov    rax,r15
0x0000000000400c23 <+50>:    add    rax,0x20
0x0000000000400c27 <+54>:    mov    rax,QWORD PTR [rax]
0x0000000000400c2a <+57>:    add    rax,0x48
0x0000000000400c2e <+61>:    mov    rax,QWORD PTR [rax]
0x0000000000400c31 <+64>:    call   rax
0x0000000000400c33 <+66>:    mov    rax,0x0
0x0000000000400c3a <+73>:    mov    rsp,rbp
0x0000000000400c3d <+76>:    pop    rbp
0x0000000000400c3e <+77>:    ret  

我最初做了一个大的"sub rsp,0x...",我认为分解它会有所帮助(它没有 - 程序在调用时崩溃)。 在这种情况下,总数应为 500MB。

真正让我感到困惑的是为什么它在"呼叫<>"而不是其中一个订阅器上失败。 以及为什么它只是在某些时候失败,而不是总是或永远不会失败。

披露:这是一个学校项目,但寻求有关 x86 的一般问题的帮助并不违反任何规则。

更新:根据@swift的评论,我设置了 ulimit -s 无限...它现在随机出现段错误? 这似乎是随机的。 它并没有接近使用整个 500 MB 缓冲区。 它总共只分配大约 400 个字节。

RSP中减去某些内容不会引起任何问题,因为没有人使用它。它只是一个带有值的寄存器,它不分配任何东西。但是,当您使用CALL时,将访问RSP指向的内存,并且可能会出现问题。堆栈通常不是很大,所以对于您的问题"是否有任何理由不能从堆栈中获取 GB 内存",答案是"因为堆栈没有那么多空间可供使用"。

至于更快地在堆栈中分配一个大的缓冲区并不是一回事。在堆中分配和释放单个大内存块的速度并不慢。堆中有大量分配和发布比堆栈中更糟糕。因此,在这种情况下,在堆栈中执行此操作没有多大意义。

最新更新