标签: calling-convention

什么是__stdcall?

我正在学习Win32编程,WinMain原型如下:

int WINAPI WinMain ( HINSTANCE instance, HINSTANCE prev_instance, PSTR cmd_line, int cmd_show )
Run Code Online (Sandbox Code Playgroud)

我很困惑这个WINAPI标识符的用途和发现:

#define WINAPI      __stdcall
Run Code Online (Sandbox Code Playgroud)

这是做什么的?在返回类型之后,我对此感到困惑.什么是__stdcall?当返回类型和函数名称之间有什么东西时,它是什么意思?

c winapi calling-convention stdcall

137
推荐指数
7
解决办法
10万
查看次数

callstack究竟是如何工作的?

我试图更深入地了解编程语言的低级操作是如何工作的,尤其是它们如何与OS/CPU交互.我可能已经在Stack Overflow上的每个堆栈/堆相关线程中阅读了每个答案,并且它们都很棒.但还有一件事我还没有完全理解.

在伪代码中考虑这个函数,这往往是有效的Rust代码;-)

fn foo() {
    let a = 1;
    let b = 2;
    let c = 3;
    let d = 4;

    // line X

    doSomething(a, b);
    doAnotherThing(c, d);
}
Run Code Online (Sandbox Code Playgroud)

这就是我假设堆栈在X行上的样子:

Stack

a +-------------+
  | 1           | 
b +-------------+     
  | 2           |  
c +-------------+
  | 3           | 
d +-------------+     
  | 4           | 
  +-------------+ 
Run Code Online (Sandbox Code Playgroud)

现在,我读到的关于堆栈如何工作的一切都是它严格遵守LIFO规则(后进先出).就像.NET,Java或任何其他编程语言中的堆栈数据类型一样.

但如果是这样,那么在X行之后会发生什么?显然,接下来我们需要的是使用ab,但这意味着操作系统/ CPU(?)必须弹出dc首先回到ab.但是它会在脚下射击,因为它需要c并且d在下一行.

所以,我想知道幕后究竟发生了什么?

另一个相关问题.考虑我们传递对其他函数的引用,如下所示:

fn foo() {
    let …
Run Code Online (Sandbox Code Playgroud)

cpu assembly callstack calling-convention low-level

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

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万
查看次数

为什么T *可以在寄存器中传递,但unique_ptr <T>无法传递?

我正在观看Chandler Carruth在CppCon 2019中的演讲:

没有零成本抽象

在该示例中,他举例说明了您对使用std::unique_ptr<int>over和会产生多少开销而感到惊讶int*。该段大约在时间点17:25开始。

您可以看一下他的示例代码对(godbolt.org)的编译结果 -可以看到,确实,编译器似乎不愿意传递unique_ptr值-实际上,底线是只是一个地址-在寄存器内,仅在直接内存中。

Carruth先生在27:00左右提出的观点之一是,C ++ ABI要求按值传递参数(某些但不是全部;也许-非基本类型?而不是在寄存器中。

我的问题:

  1. 这实际上是某些平台上的ABI要求吗?(哪个?)或者在某些情况下可能只是一些悲观?
  2. 为什么ABI这样?也就是说,如果结构/类的字段适合寄存器,甚至单个寄存器,为什么我们不能在寄存器中传递它呢?
  3. 近年来,C ++标准委员会是否曾经讨论过这一点?

PS-为了不给这个问题留下代码:

普通指针:

void bar(int* ptr) noexcept;
void baz(int* ptr) noexcept;

void foo(int* ptr) noexcept {
    if (*ptr > 42) {
        bar(ptr); 
        *ptr = 42; 
    }
    baz(ptr);
}
Run Code Online (Sandbox Code Playgroud)

唯一指针:

using std::unique_ptr;
void bar(int* ptr) noexcept;
void baz(unique_ptr<int> ptr) noexcept;

void foo(unique_ptr<int> ptr) noexcept {
    if (*ptr > 42) { 
        bar(ptr.get());
        *ptr = 42; 
    }
    baz(std::move(ptr));
}
Run Code Online (Sandbox Code Playgroud)

c++ assembly abi calling-convention unique-ptr

80
推荐指数
2
解决办法
2943
查看次数

Windows上的__cdecl或__stdcall?

我目前正在开发一个Windows的C++库,它将作为DLL发布.我的目标是最大化二进制互操作性; 更确切地说,我的DLL中的函数必须可以从使用多个版本的MSVC++和MinGW编译的代码中使用,而无需重新编译DLL.但是,我对哪种调用约定是最好的cdecl或者很困惑stdcall.

有时我会听到诸如"C调用约定是唯一一个保证编译器相同的语句"的陈述,这与诸如" 解释中存在一些变化cdecl,特别是如何返回值 "之类的陈述形成对比.这似乎并没有阻止某些库开发人员(如libsndfile)在他们分发的DLL中使用C调用约定,而没有任何明显的问题.

另一方面,stdcall调用约定似乎是明确定义的.据我所知,所有Windows编译器基本上都需要遵循它,因为它是用于Win32和COM的约定.这是基于这样的假设:没有Win32/COM支持的Windows编译器不会非常有用.在论坛上发布的很多代码片段都声明了函数,stdcall但我似乎无法找到一个明确解释原因的帖子.

那里有太多相互矛盾的信息,我运行的每一次搜索都给出了不同的答案,这些答案并没有真正帮助我在两者之间作出决定.我正在寻找一个清晰,详细,有争议的解释,为什么我应该选择一个而不是另一个(或者为什么两者是等价的).

请注意,这个问题不仅适用于"经典"函数,还适用于虚拟成员函数调用,因为大多数客户端代码将通过"接口",纯虚拟类(以下描述的模式,例如此处那里)与我的DLL接口.

c++ windows dll calling-convention binary-compatibility

76
推荐指数
3
解决办法
5万
查看次数

__stdcall的含义和用法是什么?

__stdcall这些天我经历过很多次.

MSDN没有非常清楚地解释它的真正含义,何时以及为什么要使用它,如果有的话.

如果有人提供解释,我会很感激,最好是一两个例子.

c++ windows calling-convention

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

从方法中检索调用方法名称

可能重复:
如何找到调用当前方法的方法?

我在对象中有一个方法,从对象中的许多地方调用.是否有一种快速简便的方法来获取调用此流行方法的方法的名称.

伪代码示例:

public Main()
{
     PopularMethod();
}

public ButtonClick(object sender, EventArgs e)
{
     PopularMethod();
}

public Button2Click(object sender, EventArgs e)
{
     PopularMethod();
}

public void PopularMethod()
{
     //Get calling method name
}
Run Code Online (Sandbox Code Playgroud)

在内部,PopularMethod()我希望看到Main它是否被调用的价值Main......我想看看" ButtonClick"是否PopularMethod()被调用ButtonClick

我在看,System.Reflection.MethodBase.GetCurrentMethod()但这不会让我得到调用方法.我看过这个StackTrace类,但是每次调用该方法时我都不喜欢运行整个堆栈跟踪.

c# reflection methods calling-convention

57
推荐指数
5
解决办法
7万
查看次数

什么寄存器保存在ARM C调用约定中?

自从我上次编写手臂汇编程序以来已经有一段时间了,我对细节有点生疏.如果我从arm调用C函数,我只需要担心保存r0-r3和lr,对吧?

如果C函数使用任何其他寄存器,它是否负责保存堆栈中的那些并恢复它们?换句话说,编译器会生成代码来为C函数执行此操作.

例如,如果我在汇编程序函数中使用r10,我不必将其值放在堆栈或内存中,并在C调用后弹出/恢复它,是吗?

这是针对arm-eabi-gcc 4.3.0.

c assembly arm calling-convention function-call

51
推荐指数
5
解决办法
6万
查看次数

奇怪的MSC 8.0错误:"在函数调用中没有正确保存ESP的值......"

我们最近试图将一些Visual Studio项目拆分成库,一切似乎都在一个测试项目中编译和构建,其中一个库项目作为依赖项.但是,尝试运行该应用程序给了我们以下令人讨厌的运行时错误消息:

运行时检查失败#0 - ESP的值未在函数调用中正确保存.这通常是调用使用不同调用约定声明的函数指针的结果.

我们甚至从未为函数指定调用约定(__cdecl等),使所有编译器开关都处于默认状态.我检查过,项目设置与整个库和测试项目的调用约定是一致的.

更新:我们的一个开发人员将"基本运行时检查"项目设置从"两者(/ RTC1,等同于/ RTCsu)"更改为"默认",运行时间消失,使程序运行正常.我完全不相信这一点.这是一个合适的解决方案,还是一个危险的黑客?

c++ x86 stack calling-convention visual-c++

48
推荐指数
6
解决办法
6万
查看次数

x86-64 System V ABI在哪里记录?

x86-64 System V ABI(用于除Windows之外的所有内容)过去常常访问http://x86-64.org/documentation/abi.pdf,但该网站现已脱离互联网.

该文件是否有新的权威主页?

linux assembly x86-64 abi calling-convention

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