2

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?

Expolarity
  • 153
  • 1
  • 1
  • 11
  • Because you have chosen not to use a cross compiler you have to deal with the nuances of the windows naming convention and other oddities. That applies to the native Windows compilers for Cygwin and MinGW. My understanding is that with CygWin it looks for an entry point called `___main` . You may wish to use something other than `main` to avoid this. Try using `kmain`as I believe the compiler is generating code inside `main` to call `___main` – Michael Petch Sep 28 '20 at 17:21
  • @MichaelPetch Thank you, your understanding is indeed correct, after renaming the main method to `__main` and setting the jump instruction and linker.ld file appropriately, LD proceeds to create an elf file correctly, please post this as an answer so I can close the question. – Expolarity Sep 28 '20 at 17:34

1 Answers1

1

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:

  1. https://stackoverflow.com/a/32164910/14320958
  2. https://stackoverflow.com/a/45442576/14320958

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

Expolarity
  • 153
  • 1
  • 1
  • 11