In assembly, how do you deal with C struct?

17,203

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.

Share:
17,203

Related videos on Youtube

R__
Author by

R__

Updated on June 04, 2022

Comments

  • R__
    R__ almost 2 years

    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:)

  • R__
    R__ almost 13 years
    Eldhuset,a hello world example available?
  • tc.
    tc. almost 13 years
    I think C99 guarantees that the address of a struct is the address of its first member.
  • Aasmund Eldhuset
    Aasmund Eldhuset almost 13 years
    @tc.: Sounds reasonable; I wrote "typically" just because I wasn't 100% sure that that was the case - but I can't see any reason why one would want to add padding at the start of a struct.
  • tc.
    tc. almost 13 years
    I believe C99 additionally makes it safe to cast between pointers to structs that start with the same fields and access those fields (so you can cast struct sockaddr_in* to struct sockaddr*). There's a similar guarantee which means you can use offsetof().
  • Aasmund Eldhuset
    Aasmund Eldhuset almost 13 years
    @R__: You can produce one yourself by asking the compiler to output assembly. See my updated answer.