0
votes

I am using GCC and am trying to get the linker to create an array of data objects from different files in a custom section. I have added this section to the linker script:

.mydata :
{
  __mydata_start = .;
  KEEP (*(.mydata))
  __mydata_end = .;
}

Here is my data structure:

struct my_type_t {
    unsigned char a;
    size_t b;
    void *c;
    const void *d;
    const void *e;
    const char *f;
};

I am on a 64-bit platform, and sizeof(struct my_type_t) gives 48. However, the linker seems to want to align these structures to 64-bytes.

My declarations:

struct my_type_t a1 __attribute__((section(".mydata"))) = {
    1, 2, (void *)3, (void *)4, (void *)5, (void *)6,
};
struct my_type_t a2 __attribute__((section(".mydata"))) = {
    7, 8, (void *)9, (void *)10, (void *)11, (void *)12,
};

Linker output:

$ gcc -o ldtest ldtest.c -Wl,-Tlink.ld
$ objcopy -Obinary -j .mydata ldtest mydata
$ hd mydata
00000000  01 00 00 00 00 00 00 00  02 00 00 00 00 00 00 00  |................|
00000010  03 00 00 00 00 00 00 00  04 00 00 00 00 00 00 00  |................|
00000020  05 00 00 00 00 00 00 00  06 00 00 00 00 00 00 00  |................|
00000030  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000040  07 00 00 00 00 00 00 00  08 00 00 00 00 00 00 00  |................|
00000050  09 00 00 00 00 00 00 00  0a 00 00 00 00 00 00 00  |................|
00000060  0b 00 00 00 00 00 00 00  0c 00 00 00 00 00 00 00  |................|

If I instead declare it as an array:

struct my_type_t a1[2] __attribute__((section(".mydata"))) = {
    {
    1, 2, (void *)3, (void *)4, (void *)5, (void *)6,
    },
    {
    7, 8, (void *)9, (void *)10, (void *)11, (void *)12,
    },
};

There is no padding, as expected:

00000000  01 00 00 00 00 00 00 00  02 00 00 00 00 00 00 00  |................|
00000010  03 00 00 00 00 00 00 00  04 00 00 00 00 00 00 00  |................|
00000020  05 00 00 00 00 00 00 00  06 00 00 00 00 00 00 00  |................|
00000030  07 00 00 00 00 00 00 00  08 00 00 00 00 00 00 00  |................|
00000040  09 00 00 00 00 00 00 00  0a 00 00 00 00 00 00 00  |................|
00000050  0b 00 00 00 00 00 00 00  0c 00 00 00 00 00 00 00  |................|

Why is the linker adding extra padding beyond what the compiler thinks is necessary, and how can I get rid of it?

1
"Why is the linker adding extra padding ..." - why should it not? There is no requirement in the standard about a specific placement of different objects. It is simply irrelevant for compliant C code. Regarding "how to get rid of it" you already have the answer. I don't see a problem. - too honest for this site
As I specified, these objects are in different files, so I cannot create an array out of them. However, I want to treat them as an array in C code. C thinks the size is 48, so if I increment a pointer to the first one, it will point to the padding, not to the start of the next one. - FazJaxton
"However, I want to treat them as an array in C code" - That is undefined behaviour. Sound like an XY-problem. There must be a different approach, e.g. a table of pointers. - too honest for this site
This is what Linux does to allow different drivers and subsystems to register init functions. It treats them as an array when looping through them to initialize, which is exactly what I want to do. If the linker just arbitrarily inserts padding bytes, they wouldn't be able to rely on this mechanism. - FazJaxton
Try SUBALIGN(0). - user58697

1 Answers

0
votes

I don't know why it wants it aligned on 64-byte, but you can do:

struct my_type_t {
    unsigned char a;
    size_t b;
    void *c;
    const void *d;
    const void *e;
    const char *f;
} __attribute__ ((aligned (64)));

To make gcc automatically pad each struct to the nearest higher 64-byte address and make sizeof(struct my_type_t) also include the padding. This makes operations like this work correctly:

struct my_type_t *s = &__mydata_start;
s++; // Jump to next entry
s[0]; // First entry
s[1]; // Second entry