Access array defined in inline assembler from C

2

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.

c
gcc
assembly
x86
inline-assembly
asked on Stack Overflow Nov 4, 2015 by robert • edited Sep 11, 2019 by Michael Petch

1 Answer

2

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.

answered on Stack Overflow Nov 5, 2015 by Michael Petch • edited Nov 5, 2015 by Michael Petch

User contributions licensed under CC BY-SA 3.0