Automatic data alignment can affect the addresses assigned to
labels in psects that have the NOEXE or MIX attributes. Automatic
data alignment is enabled with the .ENABLE ALIGN_DATA directive
or the /ALIGNMENT=data command-line option.
A label that occurs in a statement with a data-storage directive
is assigned the psect and offset of the storage allocated by the
data-storage directive. If the data-storage directive requires
automatic alignment, the address is assigned to the label after
automatic alignment.
The same is true of labels that occur in statements by themselves
and that are followed by a data directive in a subsequent
statement. However, if a label occurs in a statement by itself
and is followed by a statement that is not a data-storage
directive, a macro directive, a conditional directive, or a
lexical-string symbol assignment, the label is assigned the psect
and offset of the current location counter before any automatic
alignment.
The assembler only assigns addresses to labels after alignment
under the conditions previously described and only with automatic
alignment. If you place a label before a .ALIGN directive that
manually aligns the current location counter, the assembler
assigns the address of the label before performing the manual
alignment. The following example shows the interaction of label
address assignment and automatic data alignment:
.ENABLE ALIGN_DATA
.PSECT DATA, NOEXE
.BYTE 1 ; The byte is stored in psect data at offset 0
A: .PRINT "Not aligned" ; Any non-macro, nonconditional
; statement, including this .PRINT directive
; prevents A from being automatically aligned
; -- A is assigned offset 1
B: ; B is automatically aligned to offset 4
C: .LONG 2 ; C is automatically aligned to offset 4
D: .ALIGN 0 ; The .ALIGN global directive prevents D
; from being automatically aligned --
; D is assigned offset 8
E: .OCTA 3 ; E is automatically aligned to offset 16
Automatic data alignment and label-address assignment can be an
important consideration when calculating the difference between
two labels. For example, consider the following macro, which
stores a string preceded by a word that contains the string's
length:
.MACRO VARYING_STRING STRING ?L1, ?L2
.WORD L2-L1
L1: .ASCII "STRING"
L2:
.ENDM VARYING_STRING
If an invocation of the VARYING_STRING macro is followed by a
data-storage directive that requires automatic alignment, the
VARYING_STRING macro will not store the correct string length.
For example:
.PSECT DATA, NOEXE, .OCTA
.ENABLE ALIGN_DATA
VARYING_STRING <Time for something sweet!> ; 25 bytes
F: .OCTA 4
In this example, the intention is to make the L2 label generated
by the VARYING_STRING macro be assigned the offset 27, 2 for
the .WORD directive, plus 25 for the .ASCII directive. Instead,
it is assigned the offset 32 along with the label F because
the .OCTA directive requires automatic alignment to offset 32.
Therefore, the string length is incorrectly stored as 30 rather
25. To make this macro work as desired, you must include, in the
macro definition, a macro directive that is not a data-storage,
macro, or conditional directive after the generated label L2. In
the following example, .ALIGN 0 is a good choice as it reflects
the idea that the preceding label is not aligned:
.MACRO VARYING_STRING STRING ?L1, ?L2
.WORD L2-L1
L1: .ASCII "STRING"
L2: .ALIGN 0
.ENDM VARYING_STRING
With this change, the generated label L2 is assigned the offset
27 before the assembler performs automatic data alignment for the
.OCTA directive. As a result, the VARYING_STRING macro works as
desired and stores the correct string length of 25.