Andrew
Andrew

Reputation: 1445

Linking an extern static array of structs is not working correctly

I am trying to link a statically defined array of structs. I am using the extern modifier to do so. When I print out the memory address of my extern struct, it differs from the location that it appears to be in the executable.

Here is what I have:

type.h:

typedef struct tableEntry {
     const char *my_str;
     void *my_addr;
     int myint;
} my_struct;

test.c:

include "type.h"

my_struct my_array[] = {
    {"hello", (void*)15, 5000},
    {"world", (void*)15, 3000},
    {"abtest", (void*)15, 2000},
};

main.c:

#include <stdio.h>
#include "type.h"

extern my_struct* my_array;

int main() {
    printf("array location - %p\n", my_array);
    printf("array entry 1 myint - %d\n", my_array[0].myint);
    printf("array entry 1 address - %p\n", my_array[0].my_addr);
    printf("array string location - %p\n", &(my_array[0].my_str));
    printf("array string - %s\n", my_array[0].my_str);
}

I compile the program like so:

gcc test.c main.c

And when I run my executable I get the following output:

array location - 0x4006be
array entry 1 myint - 29811
array entry 1 address - 0x6574626100646c72
array string location - 0x4006be
Segmentation fault (core dumped)

my_array's address in nm output:

0000000000601060 D my_array

As you can see, my output is not what I expect, and my_array is not linked properly (the location in the nm output differs from the location printed by the actual program).

Note: I cannot include the test.c file in my main.c. It must be linked.

Upvotes: 2

Views: 1445

Answers (2)

too honest for this site
too honest for this site

Reputation: 12263

The problem with the address of my_array is you print the value the pointer contains. But for the array, you want the address of the pointer itself (which would be the address of the first element of the array). As a pointer, however, that is still wrongly declared (wonder why the compiler does not complain).

Short:

  • struct x *p; // p is the value stored in x: "where it points to"
  • struct x q[]; // q is the address of the first entry (== the address of the array).

To get the same for p, you actually would have to take &p, but that would be of type pointer to pointer, not the struct. This is one of the differences between arrays and pointers. Read the standard for details.

So, use the same declaration u used in the implementation file in main.c. Actually, you should pack the declaration into the header type.h (note this can easily be confused with the standard header type**s**.h). This iwll also generate a warning about mismatch of declaration and definition when you compile 'type.c`. That is one of the most important uses of headers actually.

For the discrepancy between the actual address and the logical address nm reports: The file is loaded to RAM before execution and has to be relocated according to the load address. The address in the file is actually relative to the base address of the .data (initialized variables) or .bss (uninitialized, default to 0 variables) section which is normally 0 for each section in the file. When loaded, start address in RAM is added to these relative addresses to get the actual address. This is one reason why a program might take some time after being loaded (relocation can be quite complicated).

There is one exception to that: if you let the linker relocate the program to absolute addresses like for an bare-metal (no full-grown OS) embedded controller, nm shall report the same addresses as during run-time or in the debugger. Reason is that the linker actually includes the job of the run-time loader described above. As a result, the code must le loaded to the correct address range, e.g. to Flash memory.

Upvotes: 3

rost0031
rost0031

Reputation: 1926

Change

extern my_struct* my_array;

To

extern my_struct my_array[];

You can't use extern to modify your array into a pointer.

Upvotes: 4

Related Questions