Page 1 of 1

QEMU crashes when calling externally linked function

Posted: Fri Jan 06, 2023 12:59 pm
by tommasopeduzzi
Hello!
I am really new to OSDev, so please excuse the potentially stupid question.
I have been following the "Calling Global Constructors" tutorial on the wiki, but I keep crashing QEMU when running my source.

Code: Select all

qemu-system-i386: ../qemu-7.2.0/accel/tcg/translator.c:175: translator_access: Assertion `phys_page != -1' failed.
.
I have tried looking up what this means, and apparently, it's that I have memory mapped IO on the second page of memory in the translation stage.
QEMU crashes when I call _init. Even when I do a ret or hlt instruction right after the label, QEMU crashes. When I comment out the call though, it correctly calls to kmain.
boot.s:

Code: Select all

// Section of data for multiboot protocol
.section .multiboot

// Multiboot magic number
.set MAGIC, 0x1BADB002
.long MAGIC

// Multiboot flags
.set ALIGN, 1 << 0
.set MEMINFO, 1 << 1
.set FLAGS, ALIGN | MEMINFO
.long FLAGS
// Multiboot checksum
.long -MAGIC-FLAGS

// Section for uninitialized data
.section .bss
// Align the stack to 16 bytes
.align 4
stack_bottom:
.skip 0x1000 // Stack is 16KB
stack_top:

// Section for code
.section .text 
.global _start
.type _start, @function
_start:
    // Set up stack
    mov $stack_top, %esp
    
    // Call _init for the global constructors
    call _init

    // Call kmain to enter kernel
    call kmain

    // Infinite loop
    cli
halt: hlt
    jmp halt

// Sets the the size of the _start symbol
.size _start, . - _start
crti.s:

Code: Select all

.section init
.global _init
.type _init, @function
_init:
    push %ebp       // Push the current base painter
    // Set the base painter to the current stack pointer, beginning a new stack frame
    movl %esp, %ebp 
    
    // The compiler will place the calls mentioned above (in this case global destructors) here

.section .fini
.global _fini
.type _fini, @function
_fini:
    // Push the current base painter
    push %ebp
    // Set the base painter to the current stack pointer, beginning a new stack frame
    movl %esp, %ebp

    // The compiler will place the calls mentioned above (in this case global destructors) here
crtn.s:

Code: Select all

.section init
_init:
    // The compiler will place the calls mentioned above (in this case global destructors) here    

    popl %ebp       // Pop the base painter from the stack resetting the stack frame
    ret    
    
.section .fini
_fini:
    // The compiler will place the calls mentioned above (in this case global destructors) here
    
    // Push the current base painter
    popl %ebp // Pop the base pointer from the stack resetting the stack frame
    ret
The project gets built and run with the following commands (please let me know if you need the Makefile):

Code: Select all

i686-elf-as crti.s -o crti.o 
i686-elf-as boot.s -o boot.o 
i686-elf-g++ -o kernel.o -c kernel.cpp -ffreestanding -O2 -Wall -Wextra -fno-exceptions -fno-rtti
i686-elf-g++ -o terminal.o -c terminal.cpp -ffreestanding -O2 -Wall -Wextra -fno-exceptions -fno-rtti
i686-elf-as crtn.s -o crtn.o 
i686-elf-g++ -T linker.ld -nostdlib -lgcc -o tos.bin crti.o /home/tommasopeduzzi/opt/cross/lib/gcc/i686-elf/12.2.0/crtbegin.o boot.o kernel.o terminal.o       /home/tommasopeduzzi/opt/cross/lib/gcc/i686-elf/12.2.0/crtend.o crtn.o
qemu-system-i386 --kernel tos.bin
Thanks in advance for the help!

Re: QEMU crashes when calling externally linked function

Posted: Sat Jan 07, 2023 12:45 am
by Octocontrabass
The wiki's guide on global constructors is very old. Every sensible ABI uses .init_array/.fini_array nowadays.

But, if you still want to investigate this, I suggest using objdump or readelf to make sure the .init section is present in your binary and has the correct attributes. From the sound of things, it either isn't being linked into the final binary or isn't in a loadable segment.

Re: QEMU crashes when calling externally linked function

Posted: Sat Jan 07, 2023 5:05 am
by tommasopeduzzi
Thanks for the reply!
It turns out that in the assembly file, I called the section "init" instead of ".init". Stupid mistake...