1
votes

How do I get rid of alignment (.align 4 below) for all global variables by default with GCC, without having to specify __attribute__((aligned(1))) for each variable?

I know that what I ask for is a bad idea to apply universally, becuase on some architectures an alignment of 1 wouldn't work, because e.g. the CPU is not able to dereference an unaligned pointer. Bit in my case I'm writing an i386 bootloader, and unaligned pointers are fine (but slower) there.

Source code (a.c):

__attribute__((aligned(1))) int answer0 = 41;
int answer = 42;

Compiled with: gcc -m32 -Os -S a.c

Assembly output (a.s):

    .file   "a.c"
    .globl  answer
    .data
    .align 4
    .type   answer, @object
    .size   answer, 4
answer:
    .long   42
    .globl  answer0
    .type   answer0, @object
    .size   answer0, 4
answer0:
    .long   41
    .ident  "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4"
    .section        .note.GNU-stack,"",@progbits

The flag gcc -fpack-struct=1 changes the alignment of all struct members and structs to 1. For example, with that flag

struct x { char a; int b; };
struct y { int v : sizeof(char) + sizeof(int) == sizeof(struct x); };
struct z { int b; };
struct x x = { 1, 1 };
int i = 42;
struct z z = { 2 };

compiles to no alignment for variables x' andz', but it still has an .align 4 for the variable i (of type int). I need a solution which also makes int i = 42; unaligned, without having to specify something extra for each such variable.

2
Is editing the linker directive file for your project an option? - Yunnosch
@Yunnosch: Yes, editing the linker script (i.e. the -Wl,-T,foo.scr) is doable. - pts
I am not sure what you want to do, but here you're just plain shooting yourself in the foot. C doesn't allow variables to be freely aligned. The __attribute__((aligned(1))) is nothing but a broken hack, and even the GCC bug tracker acknowledges it. - Antti Haapala
... because there is no way to tell the compiler that every pointer is unaligned as well... - Antti Haapala
aligned(1) does not make any sense. It is always true for any alignment. I assume that you do not understand how this attribute works. As I see the default alignment is 4. When compiler & linker see your directive it uses the default alignment as both align 4 and align 1 are the same in this case. To force variable of the size 4 to be placed between variables with size of x*4 at the odd address much more effort is needed. - 0___________

2 Answers

1
votes

IMO packing variables to save the space using the packed struct is the easiest and safest way.

example:

#include <stdio.h>
#include <stdint.h>

#define _packed __attribute__((packed))


_packed struct 
{
    uint8_t x1; 
    _packed int x2;
    _packed uint8_t x3[2];
    _packed int x4;

}byte_int;

int main(void) {
    printf("%p %p %p %p\n", &byte_int.x1, &byte_int.x2, &byte_int.x3, &byte_int.x4);
    printf("%u %u %u %u\n", (unsigned int)&byte_int.x1, (unsigned int)&byte_int.x2, (unsigned int)&byte_int.x3, (unsigned int)&byte_int.x4);    // I know it is an UB just to show the op in dec - easier to spot the odd and the even addresses

    return 0;
}

https://ideone.com/bY1soH

0
votes

Most probably gcc doesn't have such a flag which can change the default alignment of global variables.

gcc -fpack-struct=1 can be a workaround, but only for global variables which happen to be of struct type.

Also post-processing the .s output of gcc and removing (some of) the .align lines could work as a workaround.