3

I am assembling a program with nasm to fit in the boot sector (512 bytes max).

e.g. nasm -f bin boot.asm -o boot.bin

The last two lines of the program pad the remaining space with 0 and add the magic bytes:

times 510 - ($-$$) db 0 ; Pad the remaining of the first 510 bytes with 0
dw 0xaa55               ; Magic bytes required at end of boot sector

The outputted boot.bin file is always 512 bytes (expected), so I cannot trivially look at the size of boot.bin to get the size of the meaningful (non-padding and non-magic bytes) instructions.

I imagine it would work to print ($-$$) at assembly time (similar to #warning or #pragma message for gcc), but I cannot find any way to print at nasm assembly time.

Is there a clean or straightforward way to know the size of the instructions before padding?

It would be nice to avoid hacky methods like printing at runtime or searching backwards through boot.bin looking for a non-zero value.

Costava
  • 175
  • 9
  • 3
    Just ask for a listing using `-l`. Or pad the file outside of nasm using your build environment. – Jester Oct 06 '20 at 22:25
  • The comment by @Jester is the best answer. I used `-l listing.txt` to generate a listing file. In the listing file, it is plain to see the size of the meaningful instructions. – Costava Feb 17 '21 at 05:19

2 Answers2

4

You can use %assign to evaluate a numeric expression at assemble time. (Each assembly pass also uses the preprocessor. This is how you can do limited arithmetic on labels using the preprocessor.) Then use %warning to display an assemble time message. The only downside is that it'll display "as a warning", but it is assembly time output. Quoting the manual:

[...] %warning issues a warning, but allows assembly to continue:

[...]

It is optional for the message string after %error, %warning or %fatal to be quoted. If it is not, then single-line macros are expanded in it, which can be used to display more information to the user.

In my boot sector loaders I do this:

available:
    _fill 508,38,start

signatures:
    dw 0
; 2-byte magic bootsector signature
    dw 0AA55h

%assign num signatures-available
%assign fatbits 12
%if _FAT16
 %assign fatbits 16
%endif
%warning FAT%[fatbits]: num bytes still available.
%endif

end:

_fill is from the macro collection. Refer to my question about the zeros for the meaning of the first dw here.

Example output:

boot.asm:1600: warning: FAT12: 10 bytes still available. [-w+user]
ecm
  • 2,583
  • 4
  • 21
  • 29
  • 1
    That's interesting. From the name, I would have expected that a "preprocessor directive" would execute on an earlier pass, before any assembly was done or any addresses were computed, and so I wouldn't have guessed that this would work. – Nate Eldredge Oct 06 '20 at 23:46
  • @Nate Eldredge: I use this integrated preprocessor scheme's features basically in any nontrivial program. Which is the reason you can't do `nasm -E` (preprocess only) with any of my sources. Cue `error: symbol references not supported in preprocess-only mode` – ecm Oct 06 '20 at 23:55
3

You could put a label before the padding and do size: dw $-$$ to store a size in the bootloader that you could look at in an asm listing or hexdump. But that takes up 2 bytes.

nasm -fbin foo.asm -l /dev/stdout | less will display a listing of address | hexdump | source line, making it very easy to see where the time ... db 0 starts, and to the integer you put into the dw. You can see an example of that format in a code-golf answer of mine for example.


Or you can simply comment out the times 510 - ($-$$) db 0 / dw 0xaa55 padding and look at the file size!

If you're close to the limit, leave it commented out while optimizing for code size until you have something you think should fit and work.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • Is there really nothing comparable to MASM's `ECHO $`? Similar to defining `lblBEGIN EQU $` at the beginning and `ECHO $-lblBEGIN` at the end? – zx485 Oct 06 '20 at 22:34
  • @zx485: Like a CPP `#warn` equivalent for making the assembler itself do I/O at assemble time? Not that I know of; nasm keeps it simple. If you assemble into a `.o` or `.obj` with `-felf32` (or something16?) you could get symbol metadata with `nm`. – Peter Cordes Oct 06 '20 at 23:14
  • Well, ok. But I don't get the "NASM keeps it simple", because I wouldn't consider an _assemble-time output_-function to be complicated ;-) However, thanks for your answer. – zx485 Oct 06 '20 at 23:21
  • @zx485: NASM's preprocessor does have a `%warning` directive, but preprocessing happens before assembling so you can't can't warn about things that can't be known until after it's too late. – Brendan Oct 06 '20 at 23:42
  • @Brendan: Wrong, refer to my answer. `%warning` can use scalar numbers calculated by the assembler part. This is because the preprocessor is run together with the assembler for each pass. This is hinted at [in the manual](https://www.nasm.us/doc/nasmdoc4.html#section-4.9) a bit: "`%error` and `%warning` are issued only on the final assembly pass." That is they are issued only on the final pass, but are processed or handled (skipped) by the preprocessor on every pass. – ecm Oct 06 '20 at 23:49
  • @ecm: What you've overlooked is that you need something to decide if the warning should/shouldn't be used (e.g. like `%if $$-$ < 100` then `%warning "Less than 100 bytes free now!"` then `%endif`). – Brendan Oct 06 '20 at 23:53
  • @Brendan: You can do that no problem. Though it is `$ - $$` not the other way around. And you want `510 - ($ - $$)`, just `$ - $$` gives amount of bytes assembled into the current section yet. However, I'm reading the question as wanting an unconditional display. – ecm Oct 06 '20 at 23:57
  • @ecm: You can't display a number inside a warning (e.g. `%assign a $-$$` then `%warning Bytes = %a` will not work - it must be a plain string). – Brendan Oct 07 '20 at 00:00
  • @Brendan: Please try it before claiming it doesn't work. I've been using this mechanism as specified in my answer for more than 8 years now. Any modern NASM supports it. As my quote of the manual lists, you can do `%assign a $ - $$` then `%warning The number is a` to have NASM expand the `a` define in the message. – ecm Oct 07 '20 at 00:04
  • 2
    @ecm: Ah, sorry. I did try it (but tried it "wrong", without the `%[ ]` to get it to expand). – Brendan Oct 07 '20 at 00:13
  • @Brendan: The macro indirection with `%[...]` is only needed for embedding the result into another word. As in my answer, `num` is just a bare word in the `%warning` and is expanded to the define's value. – ecm Oct 07 '20 at 00:14
  • 1
    @zx485: turns out I was wrong, NASM's `%warning` *can* reference stuff like symbol offsets; see @ecm's answer. (By simple, I didn't mean really hard to implement, I meant weird from a language-design POV, like it makes it into a scripting language that can do I/O to the terminal running the assembler.) – Peter Cordes Oct 07 '20 at 02:40