Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NASM assembler - How to make sure the function label isn't executed one extra time?

Tags:

x86

assembly

Hello I am tinkering around with assembly level programming. I have the following code

    mov al, 'H'
    call my_function

my_function:
    mov ah,0x0e            ; BIOS print-character
    int 0x10
    ret

    jmp $                  ; infinite loop because there's no OS to exit to

times 510-($-$$) db 0
dw 0xaa55                  ; boot sector signature

I have a label for printing the contents of al, which is working as expected (prints H). But also after the function returns, the same label is executed again and prints an extra H. This is again understandable since ret popped the address from the stack which pointed it back to the caller and the label executed again.

Now my question is, how to avoid such circumstances? Can't I just use a label like an actual function without it printing it twice? I don't want extra executions which might alter my program.

like image 874
Pavan Avatar asked Jan 17 '18 18:01

Pavan


2 Answers

The CPU does not see your labels, it goes from instruction to instruction.

Unless the current instruction is some kind of jump (call and ret are also some kind of jumps) - after the CPU is done with current instruction, it will go to the next one, following it.

When you do call my_function, it will execute all instructions inside the function, then upon executing ret it will return back on next instruction after the call.

And the next instruction is the first instruction of the my_function again, doing it second time... After hitting ret second time it will actually get lost who-knows-where (the ret will take value at top of the stack and use it as address of next instruction, so whatever was in stack at the time of second ret happening, there's your code now running wild...)

The assembly source is not just group of instructions, but you are also positioning them in memory, and controlling the code flow, by placing one instruction after another. The CPU will execute them sequentially, line after line, just like you wrote them (except when you change the code flow by using some kind of jump, then you can jump over several lines of source).

So if you want the CPU to stop after your main is "finished", and you are creating bootloader, i.e. there's nothing to return to (no OS, or something like that), you will create dead-end at end of main by infinite loop like:

dead_end_loop:
    pause  ; give CPU hint this is idling loop
           ; so it will save power by switching off some circuitry
    jmp    dead_end_loop

And that "end of main" is right after the call my_function. "my_function" itself must be defined outside of "main", for example after this infinite loop stopper.


Maybe you missed what is jmp $ and what was it purpose in the source. The $ symbol in this case means for assembler "address of current instruction/line", so jmp $ can be translated to "jump to this same line", and that means it is an infinite loop, the CPU will never execute anything else except this jmp $ instruction (except when it was set to handle some interrupt signals, then any such external signal will cause CPU to switch execution to the particular interrupt handler code, as the programmer/OS did configured it before entering the infinite loop).


One more idea: you may want to check https://schweigi.github.io/assembler-simulator/ and "step" over the example few times to see how CPU doesn't see the source, but only the machine code bytes (visible on right side as "memory"), and how it goes from one instruction to next, how IP is changing, etc...

like image 188
Ped7g Avatar answered Nov 02 '22 22:11

Ped7g


As Jester notified in his comment, all the labels which are supposed to be functions must be below jmp $ statement so it doesn't execute an extra time.
P.S. jmp $ is instructing the system to jump to the current location which results in an infinite loop, not allowing to proceed further where the functions exist.

like image 38
Pavan Avatar answered Nov 03 '22 00:11

Pavan