我有一个使用C bison解析器的C++项目.C语法分析器使用函数指针的结构来调用函数,这些函数在生产被bison减少时创建正确的AST节点:
typedef void Node;
struct Actions {
Node *(*newIntLit)(int val);
Node *(*newAsgnExpr)(Node *left, Node *right);
/* ... */
};
Run Code Online (Sandbox Code Playgroud)
现在,在项目的C++部分,我填写了这些指针
class AstNode {
/* ... */
};
class IntLit : public AstNode {
/* ... */
};
extern "C" {
Node *newIntLit(int val) {
return (Node*)new IntLit(val);
}
/* ... */
}
Actions createActions() {
Actions a;
a.newIntLit = &newIntLit;
/* ... */
return a;
}
Run Code Online (Sandbox Code Playgroud)
现在我把它们放在其中的唯一原因extern "C"是因为我希望它们具有C调用约定.但最佳的是,我希望他们的名字仍然受到损害.它们永远不会从C代码中调用,因此名称重整不是问题.使它们受损会避免名称冲突,因为有些动作被称为error,并且C++回调函数具有丑陋的名称,如下所示只是为了避免与其他模块的名称冲突.
extern "C" {
void uglyNameError(char const *str) …Run Code Online (Sandbox Code Playgroud) 你有没有使用调用约定fastcall的真实用例?
谢谢.
我使用"StartServiceCtrlDispatcher"函数在windows中注册一个回调函数(称为ServiceMain),但我声明的回调函数是用错误的调用约定编译的.
问题是,在某些计算机上,当应用程序从回调函数返回时,应用程序崩溃,但在其他计算机上,应用程序没有崩溃.
现在,一旦我发现bug一切正常,但我只是不明白为什么在某些计算机上它能正常工作而不会崩溃?
谢谢!:-)
我找不到任何定义调用者和被调用者如何处理YMM寄存器的文档.
为了集中我的问题,这是我想知道的:
编辑:感谢下面的答案,我能够在提到的Win64文档中找到答案.我很确定Linux遵循类似的规则:
"...
The YMM registers do not have callee-save status, except for the lower half
of YMM6-YMM15 in 64-bit Windows, where XMM6-XMM15 have callee-save status.
Possible future extensions of the vector registers to 512 bits or more will not have calleesave
status.
..."
Run Code Online (Sandbox Code Playgroud) 我想学习C调用约定.为此,我编写了以下代码:
#include <stdio.h>
#include <stdlib.h>
struct tstStruct
{
void *sp;
int k;
};
void my_func(struct tstStruct*);
typedef struct tstStruct strc;
int main()
{
char a;
a = 'b';
strc* t1 = (strc*) malloc(sizeof(strc));
t1 -> sp = &a;
t1 -> k = 40;
my_func(t1);
return 0;
}
void my_func(strc* s1)
{
void* n = s1 -> sp + 121;
int d = s1 -> k + 323;
}
Run Code Online (Sandbox Code Playgroud)
然后我使用GCC使用以下命令:
gcc -S test3.c
Run Code Online (Sandbox Code Playgroud)
并想出了它的装配.我不会显示我得到的整个代码,而是粘贴函数my_func的代码.就是这个:
my_func:
.LFB1:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16 …Run Code Online (Sandbox Code Playgroud) 我正在学习再次使用汇编语言,到目前为止我遇到的唯一问题就是调用C语言.我所拥有的书是32位,而我的工作是64位.显然,调用约定存在很大差异,并且http://www.x86-64.org/documentation站点已关闭.因此,经过一些挖掘/测试,在C中编译虚拟程序并花费3天时间,我想我会发布我的发现,如果它可以帮助其他人.
RAX是否需要给出浮点数?堆栈填充"阴影空间"16或32位?这个宏用于对齐小程序的堆栈是否可以通过?我知道你可以用对齐NOP填充代码,我不确定堆栈框架.
; pf.asm compiled with 'nasm -o pf.o -f elf64 -g -F stabs'
; linked with 'gcc -o pf pf.o'
; 64-bit Bodhi (ubuntu) linux
%include "amd64_abi.mac"
[SECTION .data]
First_string: db "First string.",10,"%s", "%d is an integer. So is %d",10
db "Floats XMM0:%5.7f XMM1:%.6le XMM2:%lg",10,0
Second_String: db "This is the second string... %s's are not interpreted here.",10
db " Neither are %d's nor %f's. 'Cause it is a passed value.", 10, 0
; Just a regular string …Run Code Online (Sandbox Code Playgroud) 在C中进行函数调用时,参数以相反的顺序传递.这很重要,这样我们就可以访问第一个参数.而这一些如何支持varargs.我不明白即使你有权访问第一个参数,你仍然需要知道函数有多少个参数,否则你可能很容易忽略最后一个参数并开始将无效值视为参数.
如果参数count是必需的,那么以相反的顺序传递参数是没有意义的,因为你可以使用(sp - 2*number_of_arguments,sp = stack pointer)访问第一个参数.
以相反的顺序传递参数也应该有助于递归调用,我不明白如何.
先感谢您.
我想使用单个(交叉)编译器来编译不同ARM调用约定的代码:因为我总是想使用浮点和NEON指令,我只想选择硬浮点调用约定或软浮点数(softfp)调用约定.
我的编译器默认为hard-float,但它支持我需要的两种架构:
$ arm-linux-gnueabihf-gcc -print-multi-lib
.;
arm-linux-gnueabi;@marm@march=armv4t@mfloat-abi=soft
$
Run Code Online (Sandbox Code Playgroud)
当我使用默认参数进行编译时:
$ arm-linux-gnueabihf-g++ -Wall -o hello_world_armhf hello_world.cpp
Run Code Online (Sandbox Code Playgroud)
它成功没有任何错误.
如果我使用-print-multi-lib返回的参数进行编译:
$ arm-linux-gnueabihf-g++ -marm -march=armv4t -mfloat-abi=soft -Wall -o hello_world hello_world.cpp
Run Code Online (Sandbox Code Playgroud)
它再次编译没有错误(顺便说一句,我如何测试结果代码是硬浮动还是软浮动?)
不幸的是,如果我试试这个:
$ arm-linux-gnueabihf-g++ -march=armv7-a -mthumb-interwork -mfloat-abi=softfp -mfpu=neon -Wall -o hello_world hello_world.cpp
[...]/gcc/bin/../lib/gcc/arm-linux-gnueabihf/4.7.3/../../../../arm-linux-gnueabihf/bin/ld: error: hello_world uses VFP register arguments, /tmp/ccwvfDJo.o does not
[...]/gcc/bin/../lib/gcc/arm-linux-gnueabihf/4.7.3/../../../../arm-linux-gnueabihf/bin/ld: failed to merge target specific data of file /tmp/ccwvfDJo.o
collect2: error: ld returned 1 exit status
$
Run Code Online (Sandbox Code Playgroud)
我已经测试了一些参数的其他排列,但似乎除了-print-multi-lib所示的组合之外的任何其他结果都会导致错误.
我读过ARM编译错误,VFP注册使用的是可执行文件,而不是目标文件,但问题是二进制文件的某些部分是软的,有些是硬浮动的.我有一个C++文件来编译...
我错过了哪些参数可以用-march = armv7 -a -mthumb-interwork -mfloat-abi = softfp …
我的目标是使用__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) 我最近做了很多x64汇编编程(在Linux上),用于与我的C/C++程序集成.
由于我主要关心效率,我喜欢尽可能少地使用不同的寄存器/存储器地址,以及尝试不创建任何堆栈帧或保留寄存器(每个周期计数).
根据cdecl r10和r11寄存器不保留,我希望在我的函数中使用它们作为临时变量,最好不要保留.它是否会导致任何编译器出现任何无法解决的问题/错误(到目前为止还没有遇到任何问题,但这是一个问题)?