2013-11-01 60 views
1
__declspec(naked) void printfive() { 
    int i = 5; 
    printf("%i\n", i); 
} 

由于某些原因,此代码有效,但我不明白i存储在哪里?在调用函数的框架中?它变成全球变量?如果它存储在调用者的框架中,那么编译器如何知道位移,因为您可以使用具有不同帧大小和局部变量的不同函数调用printfive()。如果它是全球性的,或者像static也许,我试图去递归,我可以看到变量没有改变,它确实不是真正的本地。但很明显,没有入门代码(序言)。好吧,我明白,没有序言,没有框架,没有寄存器改变,但这是值,但范围?此说明符的行为是否在任何参考中定义?无论如何,这是C++标准的一部分吗?如果你主要在里面使用asm {}(或者使用asm来调用它们,并希望确保函数没有被优化),那么这种功能非常棒,但是你可以和C++混合使用。但这是一种令人费解的情绪。函数声明__declspec(naked)如何存储局部变量?

+1

你使用什么编译器? –

+0

“无论如何,这是C++标准的一部分吗?”不,你究竟想要达到什么目标?你的目标是什么?你为什么希望编写一个没有序言/ epilog的函数? –

+0

我正在实现类似于第四种线程的代码语言,每个原语都是汇编程序或C函数。大多数是asm,但有时C代码更容易阅读,裸函数并不是注册表。 – exebook

回答

1

从gcc手册:

使用该属性...来表明指定的函数不需要由编译器生成的序言/结尾序列。程序员应该提供这些序列。可以安全地包含在裸函数中的唯一语句是没有操作数的asm语句。应避免所有其他语句,包括局部变量的声明,if语句等等。应该使用裸函数来实现汇编函数的主体,同时允许编译器为汇编器构造必要的函数声明。

它是不是标准(以及任何__declspec__attribute__

+0

所以基本上它的工作原理,但它不应该工作 – exebook

+0

是的,没有人保证它会工作,如果你使用'坏'的东西。我相信这将取决于实际的CPU架构/ ABI。只要坚持安全。 – keltar

+1

@exebook:它正好适用于这种情况。但你有没有检查你的调用者的堆栈框架是否仍然完好?它的局部变量,返回地址,异常处理的东西? – MSalters

0

进入或退出一个功能时,编译器添加代码以帮助的流逝或参数。当一个函数被裸体声明时,会生成非参数变量赋值代码,如果要获取任何参数,则需要直接访问相关寄存器或堆栈(取决于ABI定义的调用约定)。

在你的情况下,你没有传递参数给函数,因此即使函数被声明为裸露,你的代码也能工作。如果你想看到不同之处,请看一下拆解程序。