标签: cdecl

在C++中,可变参数函数(在参数列表末尾带有...的函数)必须遵循__cdecl调用约定吗?

我知道__stdcall函数不能有省略号,但我想确保没有支持stdarg.h函数的平台来调用除__cdecl或__stdcall之外的约定.

c++ cdecl variadic-functions stdcall

7
推荐指数
1
解决办法
2141
查看次数

结构如何作为参数传递给汇编

结构如何作为参数传递?

由于结构的大小比正常大,各个字段是否顺序通过?

如果是这样,它们是否与正常参数相反?

他们在cdecl和stdcall之间有什么区别吗?

x86 assembly cdecl stdcall

7
推荐指数
1
解决办法
3158
查看次数

C 调用约定:谁在可变参数函数与普通函数中清理堆栈?

有一些调用约定(例如pascalstdcall),但就我而言,C 确实使用cdecl(C 声明)。这些约定中的每一个在调用者将参数加载到堆栈上的方式上都略有不同,分别是由哪个(调用者/被调用者)进行清理

谈到清理,这是我的问题。我不明白:有三种不同的东西吗?

  1. 堆栈清洁
  2. 将指针移回倒数第二个堆栈帧
  3. 堆栈恢复

或者我应该怎么看他们?

此外,这个问题的目标基本上是可变参数函数如何在像 Pascal 这样的调用约定中工作,或者stdcall被调用者应该在哪里清除/清理/恢复(我不知道哪个操作)堆栈 - 但他不知道有多少参数它会收到。

编辑

为什么将参数压入堆栈的顺序如此重要?您仍然拥有第一个参数(不是来自省略号的稳定参数),它为您提供有关 - 例如 - 变量参数数量的信息。并且还有“监护人”,它可以添加到省略号标点符号中,并且可以用作独立于调用约定的变量部分结束的标记。在这个链接中,如果调用者和被调用者在搞乱它们之前都保存了它们的状态,那么为什么调用者和被调用者都应该恢复这些寄存器的值?不应该只有其中一个(例如调用者)在调用函数之前将它们保存在堆栈中,仅此而已?另外,在同一个链接上

“因此,堆栈指针 ESP 可能会上下移动,但 EBP 寄存器保持固定。这很方便,因为这意味着我们始终可以将第一个参数称为 [EBP + 8],而不管在功能。”

推送的变量和局部变量在内存中是连续的。使用 EBP 推荐他们的优势在哪里?即使堆栈大小发生变化,它们之间也永远不会有一些动态偏移。

我读过的材料之一是这个站点(只是开始),以便更好地了解堆栈帧到底是什么。然后我继续 yt 并找到了这些堆栈概述调用堆栈教程,但他们不知何故错过了我需要的部分。当你调用函数时到底发生了什么(我不明白指令“调用地址”后跟下一个指令a push值到堆栈上,这意味着返回值)。谁来控制退货地址?呼叫者,召集者?被叫方?当被调用者返回时,程序继续执行一条指令,该指令是从寄存器中读取操作或什么?

c x86 cdecl variadic-functions calling-convention

7
推荐指数
1
解决办法
341
查看次数

C++和FULLY动态函数

我有一个绕道而行的问题.众所周知,Detours只能在5个字节的空间中移动(即'jmp'调用和4字节地址).因此,不可能在类(方法)中使用'hook'函数,你不能提供'this'指针,因为没有足够的空间(这里的问题得到了更彻底的解释).所以我整天都在集思广益寻找解决方案,现在我想要你对这个主题的想法,所以我不会在不知道是否可能的情况下开始3-5天的项目.

我最初有3个目标,我希望'hook'函数是类方法,我希望整个方法是面向对象的(没有静态函数或全局对象),而最坏/最难的部分是完全动态的.这是我的(理论上)解决方案; 使用程序集可以在运行时修改函数(一个完美的例子是任何绕行方法).因为我可以动态修改函数,我不应该也能动态创建它们吗?例如; 我分配内存,比方说~30个字节(通过malloc/new).是不是可以用对应于不同汇编运算符的二进制数替换所有字节(如0xE9是'jmp')然后直接调用地址(因为它将包含一个函数)?

注意:我事先知道返回值,以及我想要绕道的所有函数的所有参数,并且因为我使用GCC,所以thiscall约定实际上与_cdecl约定相同.

所以这是我的想法/即将实施; 我创建了一个'Function'类.此构造函数采用可变量的参数(第一个参数除外,它描述了目标函数的返回值).

每个参数都是钩子将接收的参数的描述(大小,以及它是否是指针).所以我想说我想为一个创建一个Function类int * RandomClass::IntCheckNum(short arg1);.然后我就必须这样做:Function func(Type(4, true), Type(4, true), Type(2, false));.其中'类型'定义为Type(uint size, bool pointer).然后通过程序集我可以动态创建函数(注意:这将全部使用_cdecl调用约定),因为我可以计算参数的数量和总大小.

编辑:对于示例,Type(4, true)是返回值(int*),scond Type(4, true)是RandomClass'this'指针并Type(2, false)描述第一个参数(简短arg1).

通过这个实现,我可以很容易地将类方法作为回调,但是它需要大量的汇编代码(我甚至没有特别经验).最后,唯一非动态的东西就是我的回调类中的方法(也需要前后回调).

所以我想知道; 这可能吗?它需要多少工作,我是否在这里?

编辑:我很抱歉,如果我把所有东西都弄得有些模糊,但是如果你想要更全面的解释,请问!

EDIT2:我还想知道,如果我能在某处找到所有汇编运算符的十六进制值?一份清单会有所帮助!和/或如果有可能以某种方式"保存"asm(""); 代码在内存地址(我非常怀疑).

c++ assembly detours this cdecl

6
推荐指数
1
解决办法
859
查看次数

64位C++传递具有"不同"调用约定作为参数的函数会产生不明确的错误

我的目标是使用__cdecl和__stdcall调用约定轻松提取任意函数的原型.它在32位工作正常.唯一改变的是模板函数参数中的调用约定.

根据维基百科的说法: "在Windows环境中编译x64架构时(无论是使用Microsoft还是非Microsoft工具),只有一个调用约定 - 这里描述的那个,所以stdcall,thiscall,cdecl,fastcall等. ,现在都是一样的."

这打破了64位的代码.即使调用约定相同,将函数作为参数传递仍然需要使用正确的命名法.IE如果函数定义为__stdcall,则必须将其传递给接受__stdcall的包装器.即使__cdecl相同,您仍然必须将定义为__cdecl的函数传递给接受__cdecl的包装器.

以32位工作的示例:

template<typename T, typename... Args>
struct WrapperSTD { typedef T(__stdcall *Functor)(Args...); };

template<typename T, typename... Args>
struct WrapperC { typedef T(*Functor)(Args...); };

template<typename T, typename... Args>
WrapperSTD<T, Args...> wrap(T(__stdcall *func)(Args...)) {
    return WrapperSTD<T, Args...>{};
}
template<typename T, typename... Args>
WrapperC<T, Args...> wrap(T(*func)(Args...)) {
    return WrapperC<T, Args...>{};
}
Run Code Online (Sandbox Code Playgroud)

我的目标是能够运行,例如:

using MsgBoxProto = decltype(wrap(MessageBoxA))::Functor;
Run Code Online (Sandbox Code Playgroud)

这适用于32位.但是,由于__stdcall和__cdecl在x64中显然是相同的,因此它不能在64位中工作并引发错误,表示调用是不明确的.它还告诉我模板已经定义.直观地说,似乎我能够将带有__cdecl的函数传递给这个__stdcall函数,因为编译器认为它们是相同的.但是,这不起作用:

template<typename T, typename... Args>
struct WrapperFC { typedef T(__stdcall *Functor)(Args...); };

template<typename T, typename... Args>
WrapperFC<T, Args...> wrap(T(__stdcall …
Run Code Online (Sandbox Code Playgroud)

c++ 64-bit cdecl calling-convention stdcall

6
推荐指数
1
解决办法
870
查看次数

C#/.NET Generics和Cdecl Varargs Bug?

为什么Foo()成功但却Bar()抛出了BadImageFormatException

using System.Runtime.InteropServices;
using System.Text;

static class Program
{
    [DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
    static extern int sprintf([Out] StringBuilder buf, string format, __arglist);

    static void Main(string[] args)
    {
        Foo<int>(2); //Runs fine
        Bar<int>(2); //Error: "The signature is incorrect"
    }

 static void Foo<T>(int a) { sprintf(new StringBuilder(8), "%d", __arglist(a)); }
 static void Bar<T>(T   a) { sprintf(new StringBuilder(8), "%d", __arglist(a)); }
}
Run Code Online (Sandbox Code Playgroud)

.net c# generics cdecl variadic-functions

5
推荐指数
1
解决办法
426
查看次数

__cdecl强制带下划线的前缀

我的公司为第三方提供了一个DLL,它为他们提供了可用于连接我们应用程序的API函数.DLL是用VC9编写的,API函数使用VC的默认调用约定(__cdecl).第三方围绕此界面构建了应用程序.

我现在的任务是编写DLL的更新版本.我们希望DLL具有与旧的完全相同的接口,因此它们可以互换使用.不幸的是,我们的开发环境现在是CodeGear RAD Studio 2007,因此我必须使用它来编写DLL.

最好的解决方案是使旧的和新的DLL都将其函数导出为__stdcall.然后可以重新链接第三方应用程序以期望__stdcall函数,每个人都会很高兴.不幸的是,由于各种原因,这种情况不太可能发生

或者,我可以将我的DLL中的函数声明为__cdecl.第三方期望__cdecl功能,所以这似乎是一个很好的解决方案.遗憾的是CodeGear坚持在__cdecl函数的名称后附加下划线('_').这意味着第三方应用程序必须进行有条件调用,MyApiFunction(...)或者_MyApiFunction(...)取决于它们使用的DLL.

所以我的问题是,如何从我的新DLL导出API函数,使它们是__cdecl并且带下划线('_')前缀?

c++ dll export cdecl borland-c++

5
推荐指数
1
解决办法
2332
查看次数

调用可以是cdecl或stdcall的函数

我需要编写调用外部函数的代码,该函数可以是32位Windows应用程序中的stdcall调用或cdecl。
我的代码(调用者)无法事先知道将要使用的代码。现在,如果我尝试从定义为stdcall的调用站点中调用cdecl函数,则会出现一个checkEsp异常对话框,并且我猜那是有充分原因的。
有什么办法吗?

windows assembly 32-bit cdecl stdcall

5
推荐指数
1
解决办法
398
查看次数

在CDECL调用约定中,我可以重用我压入堆栈的参数吗?

在GCC cdecl调用约定中,在调用返回后,我可以依赖于推入堆栈的参数是否相同?即使混合ASM和C并-O2启用了optimization()?

assembly gcc cdecl

5
推荐指数
1
解决办法
96
查看次数

以下代码有什么作用?

可能重复:
你如何阅读C声明?

我不明白以下几点:

int?? ?* (*(*p)[2][2])(int,int);
Run Code Online (Sandbox Code Playgroud)

你能帮我吗?

c cdecl

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