So I'm trying to compile a C file to .bin and then add it to an .img file after my first stage bootloader.
I have found these bash commands in this answer by user Michael Petch:
gcc -g -m32 -c -ffreestanding -o kernel.o kernel.c -lgcc
ld -melf_i386 -Tlinker.ld -nostdlib --nmagic -o kernel.elf kernel.o
objcopy -O binary kernel.elf kernel.bin
and used this C code (taken from the same answer, saved as kernel.c):
/* This code will be placed at the beginning of the object by the linker script */
__asm__ ("jmp _main\r\n");
int main(){
/* Do Stuff Here*/
return 0; /* return back to bootloader */
}
I executed those commands in cygwin and it produced the following result:
ld: kernel.o: in function `main':
/cygdrive/d/Work/asm/kernel.c:4: undefined reference to `___main'
objcopy: 'kernel.elf': No such file
The linker.ld
file is here:
OUTPUT_FORMAT(elf32-i386)
ENTRY(_main)
SECTIONS
{
. = 0x9000;
.text : { *(.text.start) *(.text) }
.data : { *(.data) }
.bss : { *(.bss) *(COMMON) }
}
I have dissasembled the kernel.o file using objdump
, the result of which is here:
> objdump -d -j .text kernel.o
kernel.o: file format pe-i386
Disassembly of section .text:
00000000 <.text>:
0: eb 00 jmp 2 <_main>
00000002 <_main>:
2: 55 push %ebp
3: 89 e5 mov %esp,%ebp
5: 83 e4 f0 and $0xfffffff0,%esp
8: e8 00 00 00 00 call d <_main+0xb>
d: b8 00 00 00 00 mov $0x0,%eax
12: c9 leave
13: c3 ret
Here is the result of gcc -v
if that helps also:
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-cygwin/10/lto-wrapper.exe
Target: x86_64-pc-cygwin
Configured with: /mnt/share/cygpkgs/gcc/gcc.x86_64/src/gcc-10.2.0/configure --srcdir=/mnt/share/cygpkgs/gcc/gcc.x86_64/src/gcc-10.2.0 --prefix=/usr --exec-prefix=/usr --localstatedir=/var --sysconfdir=/etc --docdir=/usr/share/doc/gcc --htmldir=/usr/share/doc/gcc/html -C --build=x86_64-pc-cygwin --host=x86_64-pc-cygwin --target=x86_64-pc-cygwin --without-libiconv-prefix --without-libintl-prefix --libexecdir=/usr/lib --with-gcc-major-version-only --enable-shared --enable-shared-libgcc --enable-static --enable-version-specific-runtime-libs --enable-bootstrap --enable-__cxa_atexit --with-dwarf2 --with-tune=generic --enable-languages=c,c++,fortran,lto,objc,obj-c++ --enable-graphite --enable-threads=posix --enable-libatomic --enable-libgomp --enable-libquadmath --enable-libquadmath-support --disable-libssp --enable-libada --disable-symvers --with-gnu-ld --with-gnu-as --with-cloog-include=/usr/include/cloog-isl --without-libiconv-prefix --without-libintl-prefix --with-system-zlib --enable-linker-build-id --with-default-libstdcxx-abi=gcc4-compatible --enable-libstdcxx-filesystem-ts
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 10.2.0 (GCC)
What am I doing wrong? Is this caused by cygwin? If yes, is there any other option I could use on windows? (I tried MSVC but that is just plainly horrible)
Also, my bootloader is not using any .section
pseudo-ops (I have no idea on how to correctly work with them), will this cause any problems in the future and will it work correctly with the compiled C program?
By deeper searching, it can be easily found out that the __main
(with an additional underscore internally) is the actual entry point for programs.
The same problem is mentioned in the following two answers:
Both of which claim some form of a connection to the -lgcc
option and the libgcc library.
Renaming main
to __main
works, but is not recommended (the entry point for kernels is apparently by convention kmain
as seen in other questions and answers)
The __main
function is what a OS calls when starting a program and it usually contains (for example) a call to exit()
(passing the return code from main
if it's return type is int) and some other underlying system calls (which are probably system specific, more research would need to be done here)
GCC expects you to include a __main
function even on standalone compilations, since it's by specification (or that's what I seen people claim) the default entry point for all applications