robert
robert

Reputation: 3726

Access array defined in inline assembler from C

I have an integer declared in Assembler, and I use it in C in the following way:

asm(
            "number:    \n"
            ".long 0xFFFFFFFF \n
);

extern int number;
int main(){
    //do something with number
}

Now I want to declare a 32 byte array in Assembler. I tried the following:

asm(
            "number:    \n"
            ".long 0xFFFFFFFF \n"
            ".long 0xFFFFFFFF \n"
            ".long 0xFFFFFFFF \n"
            ".long 0xFFFFFFFF \n"
            ".long 0xFFFFFFFF \n"
            ".long 0xFFFFFFFF \n"
            ".long 0xFFFFFFFF \n"
            ".long 0xFFFFFFFF \n"
);

extern unsigned char* number;
int main() {
    printf("%x ", number[0]); //gives segmentation fault
}

I do not really know Assembler, but I have to use for this specific variable.

Upvotes: 2

Views: 915

Answers (1)

Michael Petch
Michael Petch

Reputation: 47573

Your inline assembler does this

asm(
            "number:    \n"
            ".long 0xFFFFFFFF \n"
            [snip rest of array]
);

You then tell C that number is

extern unsigned char* number;

This says that number is a pointer to an unsigned character. Then you access it like this:

printf("%x ", number[0]);

This says to de-reference the pointer in number and return the first character. It would have been the same as doing:

printf("%x ", *(number+0));

Problem is that number was defined as a pointer. Assuming 32-bit pointers that translates to:

*(0xFFFFFFFF+0)

If you get a segfault it is probably because the address 0xFFFFFFFF is not accessible to your program.

You can change your extern statement to read:

extern unsigned char number[32];

Now number is an array of 32 unsigned characters. I'd be inclined to use the inttypes.h header and declare it as:

extern uint8_t number[32];

uint8_t is guaranteed to be 8 bits (or 1 byte). char on the other hand is defined as being a minimum of 8 bits (but can be more). However sizeof(char) will always return 1. I prefer uint8_t (unsigned 8 bit integers) just so you know you are dealing with 8 bit values which seems to be the case here. I'd modify the code to be:

#include <stdio.h>
#include <inttypes.h>

__asm__(
            "number:    \n"
            ".long 0xFFFFFFFF \n"
            ".long 0xFFFFFFFE \n"
            ".long 0xFFFFFFFF \n"
            ".long 0xFFFFFFFF \n"
            ".long 0xFFFFFFFF \n"
            ".long 0xFFFFFFFF \n"
            ".long 0xFFFFFFFF \n"
            ".long 0xFFFFFFFF \n"
);

extern uint8_t number[32];

int main() {
    printf("%x ", number[0]);
    return 0;
}

Also note that if you intend to compile using GCC as C99 (will work with GCC's C89 as well) it is preferable to use __asm__ instead of asm since GCC's default is to disable the asm keyword (unless overridden with -fasm) when using -std=c99 option.

number is probably not a good name for an array of unsigned characters. It may cause confusion when someone has to come along and maintain your code.

Upvotes: 2

Related Questions