CLOSE

The process of calling C++ functions from assembly code requires careful attention to calling conventions and function name mangling.

Step 1: Write Your C++ Function

First, write the C++ function you want to call from assembly. Make sure to declare it as extern "C" to prevent name mangling.

// example.cpp

extern "C" {
    void myFunction();
}

void myFunction() {
    // Your C++ function code here
    // For demonstration, let's print "Hello from C++" to the screen
    const char* message = "Hello from C++";
    for (int i = 0; message[i] != '\0'; ++i) {
        // Print character to screen using BIOS interrupt
        asm volatile(
            "mov $0x0E, %%ah \n"    // AH = 0Eh (Display character)
            "mov $0x07, %%bh \n"    // BH = 0 (Page number)
            "mov %0, %%al \n"      // AL = character to print
            "int $0x10 \n"          // Call BIOS video interrupt
            :
            : "m" (message[i])
            : "ah", "al", "bh"
        );
    }
}

Step 2: Write Your Assembly Code

Now, write your assembly code and call the C++ function.

section .text

extern myFunction   ; Declare the external C function

global _start      ; Entry point for the program

_start:
    ; Your assembly code here

    ; Print "Hello from Assembly" to the screen
    mov ah, 0x0E    ; AH = 0Eh (Display character)
    mov bh, 0x00    ; BH = 0 (Page number)
    mov al, 'H'     ; AL = 'H'
    int 0x10        ; Call BIOS video interrupt

    mov al, 'e'     ; AL = 'e'
    int 0x10        ; Call BIOS video interrupt

    mov al, 'l'     ; AL = 'l'
    int 0x10        ; Call BIOS video interrupt

    mov al, 'l'     ; AL = 'l'
    int 0x10        ; Call BIOS video interrupt

    mov al, 'o'     ; AL = 'o'
    int 0x10        ; Call BIOS video interrupt

    mov al, ' '     ; AL = ' '
    int 0x10        ; Call BIOS video interrupt

    mov al, 'f'     ; AL = 'f'
    int 0x10        ; Call BIOS video interrupt

    mov al, 'r'     ; AL = 'r'
    int 0x10        ; Call BIOS video interrupt

    mov al, 'o'     ; AL = 'o'
    int 0x10        ; Call BIOS video interrupt

    mov al, 'm'     ; AL = 'm'
    int 0x10        ; Call BIOS video interrupt

    mov al, ' '     ; AL = ' '
    int 0x10        ; Call BIOS video interrupt

    mov al, 'A'     ; AL = 'A'
    int 0x10        ; Call BIOS video interrupt

    mov al, 's'     ; AL = 's'
    int 0x10        ; Call BIOS video interrupt

    mov al, 's'     ; AL = 's'
    int 0x10        ; Call BIOS video interrupt

    mov al, 'e'     ; AL = 'e'
    int 0x10        ; Call BIOS video interrupt

    mov al, 'm'     ; AL = 'm'
    int 0x10        ; Call BIOS video interrupt

    mov al, 'b'     ; AL = 'b'
    int 0x10        ; Call BIOS video interrupt

    mov al, 'l'     ; AL = 'l'
    int 0x10        ; Call BIOS video interrupt

    mov al, 'y'     ; AL = 'y'
    int 0x10        ; Call BIOS video interrupt

    ; Call the C++ function
    call myFunction

    ; Infinite loop
    cli             ; Clear interrupts
.endloop:
    hlt             ; Halt processor
    jmp .endloop    ; Infinite loop

section .data
    ; Define any data variables here

section .bss
    ; Define any uninitialized variables here

Step 3: Compile and Link

Compile the C++ code and the assembly code separately and then link them together.

g++ example.o bootloader.o -o bootloader.bin -m32 -nostartfiles -nostdlib -ffreestanding

nasm -f elf32 bootloader.asm -o bootloader.o

Step 4: Create a Bootable Disk Image

Create a bootable disk image containing both the bootloader and the C++ function code.

dd if=/dev/zero of=disk.img bs=512 count=2880
dd if=bootloader.bin of=disk.img conv=notrunc

Step 5: Run Your Program

Run your program using a virtual machine like QEMU.

qemu-system-i386 -fda disk.img