Improved countdown program in x86 NASM A while back, I posted a question involving code of the same function. This post contains improved code.

From the last post, I have improved size, my work with conventions, and my comments. I was also able to minimalism memory interaction to speed things up/make things more efficient.

%define KERNEL_CALL int 80h

%define STDOUT 1
%define SYS_WRITE 4

%define EXIT 1

%define NEWLINE 0xA
%define ASCII_NUM 30h


; @params: AX - a number that is converted to ASCII, then printed
; @return: no return
%macro put_num 0
    push ax;        push ax onto the stack(for restoring value)
    add ax, ASCII_NUM;  numerical to ascii
    push ax;        push ax onto the stack(for reference by ESP)

    mov edx, 1;     message length
    mov ecx, esp;   the number from the stack pointer
    mov ebx, STDOUT
    mov eax, SYS_WRITE
    KERNEL_CALL;    logs the number to the console

    pop ax;         getting it out of the way
    pop ax;         restoring the original value of ax
%endmacro

section .text
    global _start;  for gnu linker
_start:
    push '10';      push '10' to the stack for reference by ESP

    mov edx, 2;     length
    mov ecx, esp;   message(number)
    mov ebx, STDOUT
    mov eax, SYS_WRITE
    KERNEL_CALL;    logs '10' to the console

    mov ax, 9;      initialize ax
countdown:  
    put_num;        log the current number to stdout
.subtract:
    sub ax, 1;      subtract 1

    cmp ax, 0;      compare ax with 0...
    je .blast_off;  if equal, jump to .blast_off
    jmp countdown;  if not equal, go back to countdown
.blast_off:
    mov edx, len;   message length
    mov ecx, msg;   message
    mov ebx, STDOUT
    mov eax, SYS_WRITE
    KERNEL_CALL;    logs 'Blast off!' to the console

    xor ebx, ebx
    mov eax, EXIT
    KERNEL_CALL;    exit
section .data
    msg db "Blast off!", NEWLINE
    len equ $ - msg


Output (I know - the formatting still needs work):


  10987654321Blast off!


Assembled: nasm -f elf bo7_working.s

Linked:: ld -m elf_i386 -s -o bo bo7_working.o

Some concerns:


After I learned about macros, I started to use them a lot. Am I using them in place of headers (and is this bad), or is how I am using them fine?
Am I over-using/misusing %defines (more specifically, KERNEL_CALL)?
Do I have too many or too few comments?
Are my comments unclear?
Are there any unnecessary lines? I'm a little worried about the popping at the end of put_num...
Am I following convention, or are there more things I should do?
Is my code understandable?
•After I learned about macros, I started to use them a lot. Am I using them in place of headers (and is this bad), or is how I am using them fine?  

Looks OK to me.

•Am I over-using/misusing %defines (more specifically, KERNEL_CALL)?

I wouln't use KERNAL_CALL in stead of int 80h. The latter is shorter and the value involved will not change any soon in the future.

•Do I have too many or too few comments?  

I find commenting on .subtract: a bit stating the obvious.

•Are my comments unclear?

No, they are very readable.

•Are there any unnecessary lines? I'm a little worried about the popping at the end of put_num...

The popping at the end of put_num is correct (pushing/popping 2 words in a row nicely keeps the stack aligned at dwords) but a few lines seem unnecessary to me. You do not need to compare AX with 0 since subtracting already defines the flags.
You could also shave off an extra jump.

sub ax, 1;      subtract 1
cmp ax, 0;      compare ax with 0...
je .blast_off;  if equal, jump to .blast_off
jmp countdown;  if not equal, go back to countdown
.blast_off:


Better code:

sub ax,1
jnz countdown
.blast_off:


•Am I following convention, or are there more things I should do?

The ordering of the sections of the program is a matter of taste. But I see most people put the .data section before the .text section.

•Is my code understandable?

Very understandable.