Члены struct
располагаются последовательно в памяти, возможно, с отступом, и адрес структуры обычно является адресом его первого члена.
struct Bar {
int x;
int y;
};
struct Foo {
struct Bar b;
double d;
int i;
};
struct Foo f;
Допустим, что &f
это 0x10
.Тогда &f.b.x
(первый член первого члена Foo
) также равен 0x10
.&f.b.y
- это 0x14
, поскольку f.b.x
- это четыре байта (в предположении 32-разрядного компьютера).&f.d
равно 0x18
, а &f.i
равно 0x20
.Первый адрес, который не занят f
(другими словами, &f + 1
): 0x24
.
Поэтому все, что вам нужно сделать в сборке, это убедиться, что у вас есть (стек или куча)) пространство для членов структуры, и заполните пространство соответствующими данными и передайте адрес первого члена функции.
Что касается примера, который на самом деле включает сборку, вы можете легко создать это самостоятельнонаписав небольшую тестовую программу и скомпилировав ее с gcc -S -O0 -g
, вы получите ассемблерный код для вашего C-кода.Например:
int func(struct Foo * foo) {
return foo->b.x + foo->i;
}
int main() {
struct Foo foo;
foo.b.x = 42;
foo.b.y = 9;
foo.d = 3.14;
foo.i = 8;
func(&foo);
return 0;
}
В выводе сборки, помимо прочего, вы увидите (обратите внимание: это 64-битный ASM):
movl $42, -32(%rbp)
movl $9, -28(%rbp)
movabsq $4614253070214989087, %rax
movq %rax, -24(%rbp)
movl $8, -16(%rbp)
Как видите,значения 42, 9 (целое число, битовая комбинация которого равна 3,14) и 8 загружаются в адреса -32, -28, -24 и -16 (относительно базового указателя).У меня под рукой есть только окно Solaris, поэтому я не смог использовать asmlinkage
(который указывает, что аргументы функции должны передаваться в стеке, а не в регистрах), поэтому непосредственно перед вызовом функции мы видим эффективный адресструктура загружается в регистр:
leaq -32(%rbp), %rax
movq %rax, %rdi
С asmlinkage
вы вместо этого увидите эффективный адрес, помещаемый в стек.