Home > Enterprise >  NASM assembler : How to align values using EQU, to get the next alignment boundary after a label wit
NASM assembler : How to align values using EQU, to get the next alignment boundary after a label wit

Time:12-31

I want to calculate the aligned address. 'label' should be aligned 4-byte boundary.

        bits 32
        mov eax, label
end:    ; here is the end of program
        align 4
label:

This nasm code outputs 8 bytes.

$ nasm -f bin test.nasm -o test.o
$ ndisasm -o 0x0 -b 32 test.o
00000000  B808000000        mov eax,0x8
00000005  90                nop
00000006  90                nop
00000007  90                nop

But actually the program size is 5 bytes. Is it possible to define the label without extending the program size? I expect to define 'label' as value 8 and file size of test.o will be 5.

I also tried to calculate the address using '$' variable as follows.

        bits 32
        mov eax, label
end:    ; here is the end of program
label   equ ( ($ 3) & ~3 )

But nasm does not accept this expression.

$ nasm -f bin test.nasm -o test.o
test.nasm:4: error: `&' operator may only be applied to scalar values

CodePudding user response:

This is to be expected. The absolute address of end is in general not known until after linking, so any transformations of the address would have to be computed by the linker. The linker on most systems can do some limited arithmetic (mainly addition and subtraction), which the assembler requests by inserting appropriate entries in a relocation table. This is why you can do things like mov eax, label 17 or mov eax, label2-label1. But it doesn't do fully arbitrary arithmetic like &, and there is no relocation to encode such an expression.

(I guess since we are outputting binary here, the assembler has more knowledge of absolute addresses; but it probably isn't designed to take advantage of this special case.)

So I think you're out of luck here. You can either put up with the additional bytes of padding before label, or you can do the alignment at runtime, e.g.

mov eax, label 3
and eax, ~3

CodePudding user response:

You should just use align 4.

equ is evaluated at assembly time. So it can't know the alignment of $ at runtime after linkage. Moreover, the error it is giving you,

error: `&' operator may only be applied to scalar values

that's because ($ 3) is not a scalar value. It can't even be evaluated at assembly time.

On the other hand, align 4 will pass an alignment requirement into the object file and the linker will align label correctly. If you want to validate this is correct, you can check the namelist (symbol table) on the final executable.

CodePudding user response:

As Nate explained, NASM won't do arbitrary math on addresses, even when making a flat binary instead of just writing relocations into an ELF or COFF .o / .obj.

NASM concatenates sections when making a flat binary, but doesn't emit any bytes for .bss.
This program assembles to the 5 bytes of machine code you want:

        bits 32
        mov eax, label
end:    ; here is the end of program

section .bss
        align 4       ; in the BSS where they don't end up in the file
label:
$ nasm -fbin foo.asm
$ ll foo
-rwxr-xr-x 1 peter peter 5 Dec 30 15:16 foo
$ ndisasm -b32 foo
00000000  B808000000        mov eax,0x8

I'm somewhat surprised that worked; IDK if it's officially supported or if I got lucky.
It does also work with YASM.

In FASM, even without a section .bss directive, it seems to just skip writing alignment padding at the end of the file. (So I got a 6-byte file because I didn't look up the right FASM directive for a 32-bit flat binary output, so it used a 66 operand-size prefix to encode mov eax, 8 for 16-bit mode.)

  • Related