AMD64 psABI过去曾在x86-64.org上托管.
我有一份pdf文件,它明确地说:
该体系结构规范可在网站 http://www.x86-64.org/documentation上获得.
但是http://www.x86-64.org已经很长时间了.至少几个月.
有谁知道最新的psABI可以从哪里拿走?
注意这段代码:
#include <stdio.h>
void a(int a, int b, int c)
{
char buffer1[5];
char buffer2[10];
}
int main()
{
a(1,2,3);
}
Run Code Online (Sandbox Code Playgroud)
之后 :
gcc -S a.c
Run Code Online (Sandbox Code Playgroud)
该命令在程序集中显示我们的源代码.
现在我们可以在main函数中看到,我们从不使用"push"命令将函数的参数压入堆栈.它用"movel"而不是那个
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $16, %esp
movl $3, 8(%esp)
movl $2, 4(%esp)
movl $1, (%esp)
call a
leave
Run Code Online (Sandbox Code Playgroud)
为什么会这样?他们之间有什么区别?
我正在编写一个将从汇编代码调用的C函数.
(具体来说,我想在linux内核的系统调用处理路径中做一些检查工作,所以我将在entry_32.S中调度系统调用之前调用c函数)
在定义我的c函数时,我对"asmlinkage"修饰符感到困惑.
我知道asmlinkage是告诉编译器参数将通过堆栈传递.
#define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0)))
问题:
(1)在定义将从汇编代码调用的函数时是否需要asmlinkage?
(2)gcc中的默认调用约定是什么.如果我在定义交流功能时省略"asmlinkage",它是否意味着_cdecl或fastcall?
(3)如果默认调用约定是cdecl,为什么需要asmlinkage,考虑到cdecl等于asmlinkage修饰符?(我在这里纠正吗?)
(4)为什么那些系统调用函数都是用asmlinkage声明的.我们可以先将参数复制到寄存器中,然后调用那些系统调用函数吗?从我的角度来看,在x86中,当发出系统调用时,参数很容易保存在寄存器中; 那么为什么还要在堆栈中保存然后通过堆栈约定强制执行这样的传递参数呢?
最后,任何人都可以推荐一些我可以参考混合汇编/ c编程的资源/书籍吗?
我正在使用VB6创建一个ActiveX EXE,我得到的唯一例子都是用Delphi编写的.
阅读示例代码,我注意到有一些函数的签名后跟safecall关键字.这是一个例子:
function AddSymbol(ASymbol: OleVariant): WordBool; safecall;
Run Code Online (Sandbox Code Playgroud)
这个关键字的目的是什么?
以下代码是使用VC++ 2012编译的:
void f1(void (__stdcall *)())
{}
void f2(void (__cdecl *)())
{}
void __cdecl h1()
{}
void __stdcall h2()
{}
int main()
{
f1(h1); // error C2664
f2(h2); // error C2664
f1([](){}); // OK
f2([](){}); // OK
auto fn = [](){};
f1(fn); // OK
f2(fn); // OK
}
Run Code Online (Sandbox Code Playgroud)
我认为错误是正常的,但OK可以是异常的.
所以,我的问题是:
什么是C++ lambda函数的调用约定?
如何指定C++ lambda函数的调用约定?
如果没有定义调用约定,那么在调用lambda函数后如何正确地回收堆栈空间?
编译器是否自动生成lambda函数的多个版本?即作为以下伪代码:
[] __stdcall(){};
[] __cdecl(){}; 等等
我是C的新手,有一件事我无法理解.当函数返回不大于寄存器的东西时 - 我的编译器把它放在EAX中.当我返回大结构(不是指针而是结构本身)时 - 它通过堆栈返回.
我的问题是:编译器如何知道如何调用另一个对象导出的函数?有一个调用约定(比如stdcall)但它是关于传递参数,而不是读取返回的值,对吧?
应该有一些规则,如"如果声明的返回值大于EAX,则从[bp -...]"获取.
还有一个:是否正确地说我想要返回的对象,比寄存器大,应该存储在堆中并由指针返回以防止所有堆栈操作?
谢谢.
可能重复:
在C++中通过值传递或通过常量引用传递是否更好?
我知道在C++中传递值,指针和引用的区别,我会考虑在C++中按值(而不是const引用)传递对象几乎总是编程错误.
void foo(Obj o); ... // Bad
void foo(const Obj &o); ... // Better
Run Code Online (Sandbox Code Playgroud)
唯一可以考虑通过值而不是const引用传递的地方的唯一情况是对象小于引用的位置,因此传递值更有效.
但是,这肯定是构建编译器以确定的那种东西吗?
为什么C++实际上需要传递值并通过const引用传递,并且 - 编译器是否允许自动将调用转换为(和来自)const引用(如果适用)?
(似乎有100个C++调用约定问题,询问(比如)值和引用之间的差异 - 但我找不到一个问"为什么?".)
将参数传递给函数时,我总是假设逐个传递参数与传递它们包装在数组或结构或元组中没有什么不同.然而,一个简单的实验表明我错了.
使用GCC编译时的以下程序:
int test(int a, int b, int c, int d) {
return a + b + c + d;
}
int test(std::array<int, 4> arr) {
return arr[0] + arr[1] + arr[2] + arr[3];
}
struct abcd {
int a; int b; int c; int d;
};
int test(abcd s) {
return s.a + s.b + s.c + s.d;
}
int test(std::tuple<int, int, int, int> tup) {
return std::get<0>(tup) + std::get<1>(tup) + std::get<2>(tup) + std::get<3>(tup);
}
Run Code Online (Sandbox Code Playgroud)
...产生各种装配输出:
impl_test(int, int, …
Run Code Online (Sandbox Code Playgroud) 似乎最先进的编译器将堆栈传递的参数视为只读.请注意,在x86调用约定中,调用者将参数压入堆栈,并且被调用者使用堆栈中的参数.例如,以下C代码:
extern int goo(int *x);
int foo(int x, int y) {
goo(&x);
return x;
}
Run Code Online (Sandbox Code Playgroud)
clang -O3 -c g.c -S -m32
在OS X 10.10中编译成:
.section __TEXT,__text,regular,pure_instructions
.macosx_version_min 10, 10
.globl _foo
.align 4, 0x90
_foo: ## @foo
## BB#0:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
movl 8(%ebp), %eax
movl %eax, -4(%ebp)
leal -4(%ebp), %eax
movl %eax, (%esp)
calll _goo
movl -4(%ebp), %eax
addl $8, %esp
popl %ebp
retl
.subsections_via_symbols
Run Code Online (Sandbox Code Playgroud)
这里,首先加载参数x
(8(%ebp)
)%eax
; 然后存储-4(%ebp) …
我正在阅读这本书:"计算机系统 - 程序员视角".我发现,在x86-64架构中,我们仅限于6个积分参数,这些参数将被传递给寄存器中的函数.下一个参数将在堆栈上传递.
而且,第一个最多8个FP或矢量args以xmm0..7传递.
为什么不使用浮点寄存器来存储下一个参数,即使参数不是单/双精度变量?
将数据存储在寄存器中比将其存储到存储器然后从存储器中读取它会更有效(据我所知).