Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does the ".align" x86 Assembler directive do exactly?

I will list exactly what I do not understand, and show you the parts I can not understand as well.

First off,

The .Align Directive

  1. .align integer, pad. The .align directive causes the next data generated to be aligned modulo integer bytes

1.~ ? : What is implied with "causes the next data generated to be aligned modulo integer bytes?" I can surmise that the next data generated is a memory-to-register transfer, no? Modulo would imply the remainder of a division. I do not understand "to be aligned modulo integer bytes".......

What would be a remainder of a simple data declaration, and how would the next data generated being aligned by a remainder be useful? If the next data is aligned modulo, that is saying the next generated data, whatever that means exactly, is the remainder of an integer? That makes absolutely no sense.

What specifically would the .align, say, .align 8 directive issued in x86 for a data byte compiled from a C char, i.e., char CHARACTER = 0; be for? Or specifically coded directly with that directive, not preliminary Assembly code after compiling C? I have debugged in Assembly and noticed that any C/C++ data declarations, like chars, ints, floats, etc. will insert the directive .align 8 to each of them, and add other directives like .bss, .zero, .globl, .text, .Letext0, .Ltext0.

What are all of these directives for, or at least my main asking? I have learned a lot of the main x86 Assembly instructions, but never was introduced or pointed at all of these strange directives. How do they affect the opcodes, and are all of them necessary?

like image 300
Sinister Clock Avatar asked Jun 25 '13 19:06

Sinister Clock


2 Answers

As mentioned in the comments, it means the compiler will add enough padding bytes so the next data lands on an "even" position (divisible by the alignment value). This is important because aligned memory access is much faster than unaligned memory access. (Loading a doubleword from 0x10000 is better than loading a doubleword from 0x10001). It might also be useful in case you are interfacing with other components and need to send/receive structs of data with a given padding/alignment.

like image 78
faffaffaff Avatar answered Sep 17 '22 14:09

faffaffaff


First, note that .align it is not a x86 specific concept, but a GNU GAS directive documented here. It can also be used for other architectures. x86 does not specify directives, only instructions.

Now let's play with it to understand it:

a.S

.byte 1
.align 16
sym: .byte 2

Compile and decompile:

as -o a.o a.S
objdump -Sd a.o

Output:

0000000000000000 <a-0x10>:
   0:   01 0f                   add    %ecx,(%rdi)
   2:   1f                      (bad)  
   3:   44 00 00                add    %r8b,(%rax)
   6:   66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)
   d:   00 00 00 

0000000000000010 <sym>:
  10:   02                      .byte 0x2

So sym was moved to byte 16, the first multiple of 16 after the first .byte 1 we've placed, to align it at 16 bytes.

The bytes used to fill between 01 and 02 are trash chosen by GAS (TODO how?)

Not let's try a different input:

.skip 5
.align 4
sym: .byte 2

Gives:

0000000000000000 <sym-0x8>:
   0:   00 00                   add    %al,(%rax)
   2:   00 00                   add    %al,(%rax)
   4:   00 0f                   add    %cl,(%rdi)
   6:   1f                      (bad)  
    ...

0000000000000008 <sym>:
   8:   02                      .byte 0x2

So this time sym was moved to 8, which is the first multiple of 4 that comes after 5.