标签: calling-convention

fastcall真的更快吗?

fastcall调用约定是否真的比其他调用约定更快,例如cdecl?是否有任何基准测试表明调用约定会影响性能?

c++ performance calling-convention fastcall

41
推荐指数
4
解决办法
1万
查看次数

什么是被调用者和调用者保存的寄存器?

我在理解调用者和被调用者保存的寄存器之间的区别以及何时使用什么方面遇到了一些麻烦.

我使用的是MSP430:

程序:

mov.w #0,R7 
mov.w #0,R6 
add.w R6,R7 
inc.w R6 
cmp.w R12,R6 
jl l$loop 
mov.w R7,R12
ret
Run Code Online (Sandbox Code Playgroud)

上面的代码是被调用者,并且在教科书示例中使用,因此它遵循惯例.R6和R7被呼叫者保存,R12被呼叫者保存.我的理解是被调用者保存的regs不是"全局的",因为在过程中改变它的值不会影响它在程序之外的值.这就是您必须在开头将新值保存到被调用者注册表中的原因.

R12,保存的来电者是"全球性的",因为缺乏更好的词汇.该程序在通话后对R12产生持久影响.

我的理解是否正确?我错过了其他的东西吗?

assembly abi cpu-registers calling-convention

40
推荐指数
3
解决办法
8万
查看次数

数组初始化优化

编译以下代码片段时(clang x86-64 -O3

std::array<int, 5> test()
{
    std::array<int, 5> values {{0, 1, 2, 3, 4}};
    return values;
}
Run Code Online (Sandbox Code Playgroud)

它产生了我期望的典型装配

test():                               # @test()
        mov     rax, rdi
        mov     ecx, dword ptr [rip + .L__const.test().values+16]
        mov     dword ptr [rdi + 16], ecx
        movups  xmm0, xmmword ptr [rip + .L__const.test().values]
        movups  xmmword ptr [rdi], xmm0
        ret
.L__const.test().values:
        .long   0                       # 0x0
        .long   1                       # 0x1
        .long   2                       # 0x2
        .long   3                       # 0x3
        .long   4                       # 0x4
Run Code Online (Sandbox Code Playgroud)

但是对于小型阵列,似乎已经找到了窍门?

std::array<int, 3> test()
{ …
Run Code Online (Sandbox Code Playgroud)

c++ x86-64 abi calling-convention compiler-optimization

33
推荐指数
1
解决办法
1174
查看次数

PowerShell:将函数作为参数传递

我编写了函数'A',它将调用许多其他函数之一.为了保存重写函数'A',我想传递函数作为函数'A'的参数调用.例如:

function A{
    Param($functionToCall)
    Write-Host "I'm calling : $functionToCall"
}

function B{
    Write-Host "Function B"
}

Function C{
    write-host "Function C"
}

A -functionToCall C
Run Code Online (Sandbox Code Playgroud)

返回:我正在打电话:C

我期待它回归:我在呼唤:功能C.

我尝试了各种各样的东西,比如:

Param([scriptblock]$functionToCall)
Run Code Online (Sandbox Code Playgroud)

无法将System.String转换为ScriptBlock

A -functionToCall $function:C
Run Code Online (Sandbox Code Playgroud)

返回"写主机"功能C"

A - functionToCall (&C)
Run Code Online (Sandbox Code Playgroud)

这在其余部分之前进行评估:

 Function C
 I'm Calling :
Run Code Online (Sandbox Code Playgroud)

我确定这是编程101,但我无法弄清楚正确的语法或它是什么我做错了.我们将非常感激地提供任何帮助.非常感谢.

powershell parameter-passing calling-convention

32
推荐指数
5
解决办法
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
查看次数

如何声明__stdcall函数指针

我试过这个

typedef void (* __stdcall MessageHandler)(const Task*);
Run Code Online (Sandbox Code Playgroud)

这编译但给了我这个警告(VS2003):

警告C4229:使用的时间错误:忽略数据上的修饰符

我想用stdcall调用约定声明一个指向函数的指针?我究竟做错了什么?

c++ function-pointers calling-convention visual-c++

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

为什么 std::tuple 会破坏 C++ 中的小型结构调用约定优化?

C++ 具有小型结构调用约定优化,其中编译器在函数参数中传递小型结构与传递原始类型(例如,通过寄存器)一样有效。例如:

class MyInt { int n; public: MyInt(int x) : n(x){} };
void foo(int);
void foo(MyInt);
void bar1() { foo(1); }
void bar2() { foo(MyInt(1)); }
Run Code Online (Sandbox Code Playgroud)

bar1()bar2()生成几乎相同的汇编代码,除了分别调用foo(int)foo(MyInt)。特别是在 x86_64 上,它看起来像:

        mov     edi, 1
        jmp     foo(MyInt) ;tail-call optimization jmp instead of call ret
Run Code Online (Sandbox Code Playgroud)

但是如果我们测试std::tuple<int>,它会有所不同:

void foo(std::tuple<int>);
void bar3() { foo(std::tuple<int>(1)); }

struct MyIntTuple : std::tuple<int> { using std::tuple<int>::tuple; };
void foo(MyIntTuple);
void bar4() { foo(MyIntTuple(1)); }
Run Code Online (Sandbox Code Playgroud)

生成的汇编代码看起来完全不同,小尺寸的struct( std::tuple<int>)是通过指针传递的:

        sub     rsp, 24 …
Run Code Online (Sandbox Code Playgroud)

c++ x86 calling-convention c++11 stdtuple

29
推荐指数
2
解决办法
1292
查看次数

C编译器如何实现返回大型结构的函数?

函数的返回值通常存储在堆栈或寄存器中.但对于大型结构,它必须在堆栈上.在这个代码的真实编译器中必须进行多少复制?还是优化了?

例如:

struct Data {
    unsigned values[256];
};

Data createData() 
{
    Data data;
    // initialize data values...
    return data;
}
Run Code Online (Sandbox Code Playgroud)

(假设函数无法内联..)

c compiler-theory abi calling-convention compiler-optimization

24
推荐指数
3
解决办法
6767
查看次数

如果我不包含标题,为什么在调用函数之前清除 EAX?

在以下 C 代码中:

#include <stdio.h>
int main(void){getchar();}
Run Code Online (Sandbox Code Playgroud)

它产生以下汇编:

main:
        push    rbp
        mov     rbp, rsp
                 # no extra instruction here when header is included
        call    getchar
        mov     eax, 0
        pop     rbp
        ret
Run Code Online (Sandbox Code Playgroud)

但是,如果我不包含stdio.h在文件中,那么它仍然可以编译,但会添加看起来像随机mov eax, 0指令的内容:

在此处输入图片说明

这是编译器资源管理器:https : //godbolt.org/z/3fTcss。这只是“未定义行为”的一部分,还是有特殊原因将之前的指令call getchar添加到那里?

c assembly x86-64 calling-convention

24
推荐指数
1
解决办法
1624
查看次数

如何在gcc中实现变量参数?

int max(int n, ...)
Run Code Online (Sandbox Code Playgroud)

我正在使用cdecl调用约定,其中调用者在被调用者返回后清理变量.

我想知道怎么做宏va_end,va_startva_arg工作?

调用者是否将参数数组的地址作为max的第二个参数传递?

c gcc variadic-functions calling-convention

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