Рассмотрим эту простую функцию:
struct Foo {
int a;
int b;
int c;
int d;
int e;
int f;
};
Foo foo() {
Foo f;
f.a = 1;
f.b = 2;
f.c = 3;
f.d = 4;
f.e = 5;
f.f = 6;
return f;
}
Она генерирует следующую сборку:
0000000000400500 <foo()>:
400500: 48 ba 01 00 00 00 02 movabs rdx,0x200000001
400507: 00 00 00
40050a: 48 b9 03 00 00 00 04 movabs rcx,0x400000003
400511: 00 00 00
400514: 48 be 05 00 00 00 06 movabs rsi,0x600000005
40051b: 00 00 00
40051e: 48 89 17 mov QWORD PTR [rdi],rdx
400521: 48 89 4f 08 mov QWORD PTR [rdi+0x8],rcx
400525: 48 89 77 10 mov QWORD PTR [rdi+0x10],rsi
400529: 48 89 f8 mov rax,rdi
40052c: c3 ret
40052d: 0f 1f 00 nop DWORD PTR [rax]
На основании сборки я понимаю, что вызывающая сторона создала пространство для Foo
на своей и передал эту информацию в rdi
вызываемому объекту.
Я пытаюсь найти документацию для этого соглашения. Соглашение о вызовах в linux гласит, что rdi
содержит первый целочисленный аргумент. В этом случае foo
не имеет никаких аргументов.
Более того, если я заставлю foo
принять один целочисленный аргумент, он теперь передается как rsi
(регистр для второго аргумента) с использованием rdi для адреса возвращаемого объекта.
Может ли кто-нибудь предоставить некоторую документацию и пояснить, как rdi
используется в системе V ABI?