相关疑难解决方法(0)

Why does Windows64 use a different calling convention from all other OSes on x86-64?

AMD has an ABI specification that describes the calling convention to use on x86-64. All OSes follow it, except for Windows which has it's own x86-64 calling convention. Why?

Does anyone know the technical, historical, or political reasons for this difference, or is it purely a matter of NIHsyndrome?

I understand that different OSes may have different needs for higher level things, but that doesn't explain why for example the register parameter passing order on Windows is rcx - rdx …

windows x86-64 calling-convention

97
推荐指数
4
解决办法
2万
查看次数

堆栈分配,填充和对齐

我一直在努力深入了解编译器如何生成机器代码,更具体地说是GCC如何处理堆栈.在这样做的过程中,我一直在编写简单的C程序,将它们编译成汇编并尽力理解结果.这是一个简单的程序及其生成的输出:

asmtest.c:

void main() {
    char buffer[5];
}
Run Code Online (Sandbox Code Playgroud)

asmtest.s:

pushl   %ebp
movl    %esp, %ebp
subl    $24, %esp
leave
ret
Run Code Online (Sandbox Code Playgroud)

让我感到困惑的是为什么要为堆栈分配24个字节.我知道由于处理器如何寻址内存,堆栈必须以4为增量进行分配,但如果是这种情况,我们应该只将堆栈指针移动8个字节而不是24个.作为参考,缓冲区为17 bytes产生一个移动40个字节的堆栈指针,并且根本没有缓冲区移动堆栈指针8. 1到16个字节之间的缓冲区移动ESP24个字节.

现在假设8个字节是必要的常量(它需要什么?),这意味着我们分配16个字节的块.为什么编译器会以这种方式对齐?我正在使用x86_64处理器,但即使是64位字也只需要8字节对齐.为什么会出现差异?

作为参考,我正在使用gcc 4.0.1运行10.5的Mac上进行编译,并且未启用任何优化.

c x86 assembly stack gcc

45
推荐指数
2
解决办法
2万
查看次数

什么是"堆栈对齐"?

什么是堆栈对齐?为什么用它?可以通过编译器设置来控制吗?

这个问题的细节来自于尝试将ffmpeg库与msvc一起使用时遇到的问题,但我真正感兴趣的是对"堆栈对齐"的解释.

细节:

  • 当runnig我的msvc编译程序链接到avcodec我得到以下错误:"编译器没有对齐堆栈变量.Libavcodec已被错误编译",随后avcodec.dll崩溃.
  • avcodec.dll没有用msvc编译,所以我无法看到里面发生了什么.
  • 运行ffmpeg.exe并使用相同的avcodec.dll时一切正常.
  • ffmpeg.exe没有用msvc编译,它符合gcc/mingw(与avcodec.dll相同)

谢谢,

担

c++ compiler-construction mingw visual-c++ data-structures

44
推荐指数
3
解决办法
2万
查看次数

为什么Mac ABI需要x86-32的16字节堆栈对齐?

我可以理解旧PPC RISC系统的这个要求,甚至是x86-64,但是对于旧的,经过验证的x86?在这种情况下,堆栈只需要在4字节边界上对齐.是的,某些MMX/SSE指令需要16字节对齐,但如果这是被调用者的要求,则应确保对齐正确.为什么要为每个来电者增加这项额外要求?这实际上可能会导致性能下降,因为每个呼叫站点都必须管理此要求.我错过了什么吗?

更新:在对此进行一些调查并与一些内部同事进行一些咨询后,我对此有一些理论:

  1. PPC,x86和x64版操作系统之间的一致性
  2. 似乎GCC codegen现在始终执行子esp,xxx然后将数据"移动"到堆栈而不是简单地执行"推送"指令.在某些硬件上,这实际上可能更快.
  3. 虽然这确实使调用站点变得复杂,但是当使用默认的"cdecl"约定时,调用者清理堆栈时几乎没有额外的开销.

我对最后一项的问题是,对于依赖于被调用者清理堆栈的调用约定,上述要求实际上 "uglify"了codegen.例如,某些编译器决定为自己的内部使用实现更快的基于寄存器的调用样式(即任何不打算从其他语言或源调用的代码)?这种堆栈对齐可能会通过在寄存器中传递一些参数来抵消一些性能提升.

更新:到目前为止,唯一真正的答案是一致性,但对我来说,答案有点太容易了.我有超过20年的x86架构经验,如果一致性,而不是性能,或其他具体的东西,那么我真的是因为我恭敬地建议开发人员要求它有点天真.他们忽略了近三十年的工具和支持.特别是如果他们期望工具供应商能够快速轻松地为他们的平台调整他们的工具(可能不是......这是 Apple ......),而不必跳过几个看似不必要的箍.

我会在另一天左右给出这个话题,然后关闭它......

有关

macos stack alignment abi calling-convention

31
推荐指数
3
解决办法
6714
查看次数

为什么GCC的VLA(可变长度数组)实现中有数字22?

int read_val();
long read_and_process(int n) {
    long vals[n];
    for (int i = 0; i < n; i++)
        vals[i] = read_val();
    return vals[n-1];
}
Run Code Online (Sandbox Code Playgroud)

x86-64 GCC 5.4编译的汇编语言代码为:

read_and_process(int):
        pushq   %rbp
        movslq  %edi, %rax
>>>     leaq    22(,%rax,8), %rax
        movq    %rsp, %rbp
        pushq   %r14
        pushq   %r13
        pushq   %r12
        pushq   %rbx
        andq    $-16, %rax
        leal    -1(%rdi), %r13d
        subq    %rax, %rsp
        testl   %edi, %edi
        movq    %rsp, %r14
        jle     .L3
        leal    -1(%rdi), %eax
        movq    %rsp, %rbx
        leaq    8(%rsp,%rax,8), %r12
        movq    %rax, %r13
.L4:
        call    read_val()
        cltq …
Run Code Online (Sandbox Code Playgroud)

c assembly gcc x86-64 variable-length-array

14
推荐指数
1
解决办法
887
查看次数

将XMM寄存器推入堆栈

有没有办法将打包的双字整数从XMM寄存器推送到堆栈?然后在需要时弹出它?

理想情况下,我正在寻找像PUSH或POP这样的通用寄存器,我已经检查了英特尔手册,但我要么错过了命令,要么没有一个...

或者我是否必须将值解压缩到通用寄存器然后推送它们?

x86 assembly sse simd

13
推荐指数
1
解决办法
8505
查看次数

Microsoft Stack 是否始终与 16 字节对齐?

在Kip Irvine 的《Assembly Language, Seventh Edition for x86 Processors》第 211 页中,它在5.53 The x86 Calling Convention下说,它解决了 Microsoft x64 Calling Convention,

  1. 调用子程序时,堆栈指针 ( RSP) 必须在 16 字节边界(16 的倍数)上对齐。该CALL指令将 8 字节返回地址压入堆栈,因此调用程序除了已经为影子空间减去 32 之外,还必须从堆栈指针中减去 8 。

它继续显示一些sub rsp, 8在 之前带有 的程序集sub rsp, 20h(对于 32 字节的影子空间)。

但这是一个安全的约定吗?Microsoft 堆栈是否保证在指令之前按 16 字节对齐CALL?或者,这本书假设堆栈是错误的

  1. 对齐到之前的 16 字节CALL
  2. 将 8 字节返回地址压入堆栈CALL
  3. 需要额外的操作sub rsp, 8;才能恢复到 16 字节对齐吗?

windows assembly stack x86-64 calling-convention

10
推荐指数
1
解决办法
2155
查看次数

为什么 GCC 在堆栈上分配的空间超出了必要的空间,超出了对齐所需的空间?

我正在阅读一本教科书,其中显示了基于 C 代码的汇编代码:

代码:

void echo()
{
   char buf[8];
   otherFunction(buf);
}
Run Code Online (Sandbox Code Playgroud)

汇编代码:

echo:
   subq $24, %rsp      //Allocate 24 bytes on stack, but why allocate 24 instead of 8 bytes?
   movq %rsp, %rdi     //Compute buf as %rsp
   call otherFunction  
Run Code Online (Sandbox Code Playgroud)

我不明白为什么堆栈指针%rsp会减少 24 个字节。我只将 8 个字节的缓冲区分配为char buf[8];,并且没有被调用者保存的寄存器压入堆栈,指令不应该是

subq $8, %rsp
Run Code Online (Sandbox Code Playgroud)

c assembly gcc callstack x86-64

9
推荐指数
2
解决办法
362
查看次数

x86程序集中堆栈对齐的响应性

我试图清楚地了解谁(调用者或被调用者)负责堆栈对齐.64位汇编的情况相当清楚,它是由调用者.

参考System V AMD64 ABI,第3.2.2节"堆栈帧":

输入参数区域的末尾应在16(32,如果在堆栈上传递__m256)字节边界上对齐.

换句话说,应该可以安全地假设,对于被调用函数的每个入口点:

16 | (%rsp + 8)

保持(额外八个是因为call隐含地在堆栈上推送返回地址).

它在32位世界中的表现(假设是cdecl)?我注意到,使用以下构造gcc将对齐放置在被调用函数内:

and esp, -16
Run Code Online (Sandbox Code Playgroud)

这似乎表明,这是被召唤者的责任.

为了更清楚,请考虑以下代码:

global main
extern printf
extern scanf
section .rodata
    s_fmt   db "%d %d", 0
    s_res   db `%d with remainder %d\n`, 0
section .text
main:
    start   0, 0
    sub     esp, 8
    mov     DWORD [ebp-4], 0 ; dividend
    mov     DWORD [ebp-8], 0 ; divisor

    lea     eax, [ebp-8]
    push …
Run Code Online (Sandbox Code Playgroud)

linux x86 assembly gcc memory-alignment

8
推荐指数
1
解决办法
4196
查看次数

为什么 GCC 分配的堆栈内存比需要的多?

我正在阅读“计算机系统:程序员的视角,3/E”(CS:APP3e),以下代码是书中的示例:

long call_proc() {
    long  x1 = 1;
    int   x2 = 2;
    short x3 = 3;
    char  x4 = 4;
    proc(x1, &x1, x2, &x2, x3, &x3, x4, &x4);
    return (x1+x2)*(x3-x4);
}
Run Code Online (Sandbox Code Playgroud)

书中给出了GCC生成的汇编代码:

long call_proc()
call_proc:
    ; Set up arguments to proc
    subq    $32, %rsp           ; Allocate 32-byte stack frame
    movq    $1, 24(%rsp)        ; Store 1 in &x1
    movl    $2, 20(%rsp)        ; Store 2 in &x2
    movw    $3, 18(%rsp)        ; Store 3 in &x3
    movb    $4, 17(%rsp)        ; Store 4 in …
Run Code Online (Sandbox Code Playgroud)

c gcc x86-64 compiler-optimization stack-memory

8
推荐指数
1
解决办法
678
查看次数