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.)