Posts: 108
Joined: Mon Sep 10, 2012 4:14 pm

Checking alignment in asm

Thu Mar 13, 2014 11:34 am

In optimising my memset routine, I'd really like to insert some assembler pre-processor directives to fail the assembler in the event that a given label is not aligned on a 32-byte boundary. I have tried the following:

.if (. & 31 != 0)

This produces an error from the assembler: Error: non-constant expression in ".if" statement. I guess that's because the actual value of '.' may vary depending on where the module is loaded (?) although if . is the offset from module start it really should be an absolute value.
The documentation for operators says "Apart from + or -, both arguments must be absolute, and the result is absolute". So I tried a different approach, assuming that the module entry point is 32-byte aligned:

.if ( (. - _moduleStart & 31) != 0)

This produces the expected abort and works if its aligned. However if I have a .align anywhere before this, I go back to the non-constant expression error. Anybody know if there's some other way to reliably check whether the current module offset is a multiple of 32 or not?

Posts: 108
Joined: Mon Sep 10, 2012 4:14 pm

Re: Checking alignment in asm

Thu Mar 13, 2014 12:34 pm

This is what I've ended up using. A macro that defines a label and produces an error if its not 32-byte aligned, indicating how many nop instructions are required before that label to align it:

Code: Select all

.macro ALIGNED_32 label
.equ _align_\label, (. - _module_start) & 31
.if ( _align_\label == 0 )
.elseif ( _align_\label == 4 )  ; .error "\label is not aligned: 7 nops required";
.elseif ( _align_\label == 8 )  ; .error "\label is not aligned: 6 nops required";
.elseif ( _align_\label == 12 ) ; .error "\label is not aligned: 5 nops required";
.elseif ( _align_\label == 16 ) ; .error "\label is not aligned: 4 nops required";
.elseif ( _align_\label == 20 ) ; .error "\label is not aligned: 3 nops required";
.elseif ( _align_\label == 24 ) ; .error "\label is not aligned: 2 nops required";
.elseif ( _align_\label == 28 ) ; .error "\label is not aligned: 1 nop required";

# example usage:
ALIGNED_32 my_loop
    b my_loop

test.s:57: Error: my_loop is not aligned: 1 nop required
Not sure there's any way to have the assembler actually include the required nops, apart from using .align directives, but typically that puts the nops inline in the code path rather than outside.

Return to “Bare metal, Assembly language”