yomol777
yomol777

Reputation: 463

How to access C struct value in assembly?

When I want to access some value in C struct in assembly, I usually just add something to the struct's address. However, when this struct is large, it's quite a bit tiring... Is there any trick or normal option to declare global label inside?

How to access C struct value in assembly?

Upvotes: 3

Views: 2378

Answers (2)

rcgldr
rcgldr

Reputation: 28931

If the structure is not too complicated, try a web search for "masm h2inc". H2INC.EXE (also needs H2INC.ERR) is an old Microsoft utility that will convert a .h file for a C program into a .inc file for MASM. Although this is part of a 16 bit toolset, the programs are 32 bit programs that use a dos extender and will run on Win XP, Win 7 64 bit, but I haven't tested Win 10 64 bit.

It doesn't seem to support 64 bit integers or 64 bit pointers (since it was mean for 16 bit Microsoft C code). You could work with a modified .h file and then post fix the .inc file.

There are other versions of h2inc from third parties that can support more current features, some of which will show up in a search for "masm h2inc".

Upvotes: 0

Ajay Brahmakshatriya
Ajay Brahmakshatriya

Reputation: 9213

To get the addresses of individual members, like you rightly pointed out, you have to add a constant offset to the address of the struct. The problem essentially boils down to automatically calculating these offsets for a given struct and member.

Even for small structs, I would suggest not calculating the offsets by hand because compilers add different padding between members and hints like __attribute__(packed) are not available for all compilers.

For most of my projects I use a separate program to generate an offsets header at build time.

The basic idea is to create a .c/.cpp file with something like -

// Your program headers that define the structs here
#include <stdio.h>
#include <stddef.h>

#define OFFSET(x, str, mem) printf("#define " #x " %d\n",(int) offsetof(str, mem))
#define SIZE(x, str) printf("#define " #x " %d\n", (int) sizeof(str))
#define HEADER_START() printf("#ifndef ASM_OFFSET_H\n#define ASM_OFFSET_H\n")
#define HEADER_END() printf("#endif\n")

int main(int argc, char *argv[]) {

    HEADER_START();

    OFFSET(struct_name_member_name, struct_name, member_name); // Substitute your struct name and member name here

    SIZE(struct_name_size, struct_name); // This macro is to get the size of a struct

    HEADER_END();

    return 0;
}

Executing this program during the build time generates a header file that can be included directly with GASM. For other assemblers you can change the syntax to generate appropriate inc files.

The benefit of this approach is that the program uses the same headers as your C/C++ code. That way when you change any headers, the generated offsets should change automatically.

One thing you have to be careful here is that this technique does not work well if you are cross compiling for a different architecture and the compiler uses a different layout on your host vs the target. If you want something similar for cross compilation, I can write a separate answer.

Upvotes: 5

Related Questions