assemblyx86x86-16

How to change addresses of opcodes in executable binary files x86 16bit assembly?


I have a basic bootloader that reads my kernel at 0x0500. The kernel do some setup then reads and calls a binary.

Executable Binary:

BITS 16
ORG 0x0000
START_ADDR dw init ;The address to be called from kernel.
times 16-($-$$) db 0 ;Reserved

init:
    mov ah, 0x04 ;Print str function
    mov si, [STR_TO_PRINT]
    int 0x20 ;Call kernel GPU driver
    jmp short main

main:
    jmp short main

STR_TO_PRINT db "Hello", 0

times 512-($-$$) db 0 ;just to fill sector

The kernel is loading this binary to a free area in RAM. For example in 0x4000 or 0x7C00 or 0x8000 depends on what other binaries are loaded into RAM. Kernel reads the START_ADDR word and do the where loaded + START_ADDR (e.g. 0x7C00 + 0x0010 = 0x7C10) and the code starts to be executed correctly.

It uses jmp short so there are relative jmp so there is no problem with where is the binary loaded into RAM, but STR_TO_PRINT has the address of the file and not that in the RAM. (e.g. STR_TO_PRINT is at 0x0020 (File) and in the ram is at 0x7C20 (RAM) but the string got print in the screen is the data at 0x0020 (RAM).

How to make it point to the correct address?

I am using NASM assembler. Both kernel and binary works in Real Mode 16bit


Solution

  • times 16($-$$) db 0 ;Reserved
    

    This should be times 16-($-$$) db 0

    mov si, [STR_TO_PRINT]
    

    For NASM the correct way to retrieve the address of the message is either lea si, [STR_TO_PRINT] (4 bytes) or mov si, STR_TO_PRINT (3 bytes).


    I tried setting DS and using far jmp in order to change the CS, but this caused problems with the kernel interrupts. And the program didn't worked

    KISS - Why not have the kernel pass the load address in a register like BP? That way the program can patch the sole argument SI before invoking the print service. Normally this should not cause problems with your existing kernel interrupts.

    BITS 16
    ORG 0x0000
    START_ADDR dw init ; The address to be called from kernel.
    times 16-($-$$) db 0 ;Reserved
    ; ----------------
    init:
        lea si, [bp+STR_TO_PRINT]
        mov ah, 0x04               ;Print str function
        int 0x20                   ;Call kernel GPU driver
        jmp short main
    
    main:
        jmp short main
    
    STR_TO_PRINT db "Hello", 0
    
    times 512-($-$$) db 0 ;just to fill sector