Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In assembly, how do you deal with C struct?

For example, how to prepare parameters for this syscall sys_wait4:

 asmlinkage long sys_wait4(pid_t pid,unsigned int __user *stat_addr, int options, struct rusage __user *ru)
1120 {

How to deal with struct rusage in assembly?

A hello world example to deal with struct in assembly is enough for me:)

like image 608
R__ Avatar asked Jul 01 '11 15:07

R__


People also ask

How are structs passed in assembly?

Structures, like arrays, are passed by reference, so as a parameter: they are just a 32-bit parameter (the pointer to the first structure member), and that pointer is pushed on the stack in the cases of cdecl and stdcall .

What is structure in assembly language?

Data structures in assembly language, as in high-level languages, are nested structures composed of references, structs, and arrays. These structures are often dynamically allocated, which gives programs the capability of adjusting their memory usage to the immediate needs.


1 Answers

The members of a struct are laid out sequentially in memory, possibly with padding, and the address of the struct is typically the address of its first member.

struct Bar {
    int x;
    int y;
};

struct Foo {
    struct Bar b;
    double d;
    int i;
};

struct Foo f;

Let's say that &f is 0x10. Then, &f.b.x (the first member of the first member of Foo) is also 0x10. &f.b.y is 0x14, since f.b.x is four bytes (assuming a 32-bit machine). &f.d is 0x18, and &f.i is 0x20. The first address that is not occupied by f (in other words, &f + 1) is 0x24.

So all you need to do in assembly is to make sure that you have (stack or heap) space for the members of the struct, and fill the space with appropriate data, and pass the address of the first member to the function.

As for an example that actually involves assembly, you could easily produce that yourself by writing a small test program and compile it with gcc -S -O0 -g, which will produce assembly code for your C code. For example:

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;
}

In the assembly output, you will, among other things, see (note: this is 64-bit ASM):

movl    $42, -32(%rbp)
movl    $9, -28(%rbp)
movabsq $4614253070214989087, %rax
movq    %rax, -24(%rbp)
movl    $8, -16(%rbp)

As you can see, the values 42, 9, (integer whose bit pattern is that of 3.14), and 8 being loaded into the addresses -32, -28, -24, and -16 (relative to the base pointer). I only have a Solaris box handy, so I couldn't use asmlinkage (which specifies that the function arguments must be passed on the stack rather than in the registers), so immediately before the function call, we see the effective address of the struct being loaded into a register:

leaq    -32(%rbp), %rax
movq    %rax, %rdi

With asmlinkage, you'd instead see this effective address being pushed onto the stack.

like image 126
Aasmund Eldhuset Avatar answered Sep 22 '22 13:09

Aasmund Eldhuset