3

I am learning Operating system tutorials. I created 2 files.

  1. boot.asm
  2. kernel.c

The kernel.c is as follows :

int main()
{
  char *src = (char *)0xB8000000L;
  *src = 'M';
  src += 2;
  *src = 'D';
  return 0;
}

The kernel is used to write a character to the text mode video display area. The kernel was compiled using Windows version of GCC with:

gcc -ffreestanding -c -m16 kernel.c -o kernel.o

I link the kernel object to a binary file using LD:

ld -Ttext 0x10000 --oformat binary -o kernel.bin kernel.o

The error I get is:

ld : cannot link the file which is not PE executable type

Can anybody solve this error?

  • OS used : windows
  • compiler : GCC
  • Linker : ld
Ross Ridge
  • 38,414
  • 7
  • 81
  • 112
Panther Coder
  • 1,058
  • 1
  • 16
  • 43
  • Besides the linker problem, are you trying to convert old TurboC/MSVC 16-bit code to _GCC_? I find `(char *)0xB8000000L` suspicious. If it was a true 16-bit C compiler it might be okay if it was `(char far *)0xB8000000L`. _GCC_ is not a true 16-bit C compiler and doesn't have a notion of old style `far` pointers. So even if you get this code to compile this may not do what you think it does, I'm assuming from the `-m16` option with _GCC_ you are trying to create a real-mode 16-bit kernel (rather than a protected mode one)? – Michael Petch May 20 '16 at 16:28
  • Yes that right. I am trying to print text on screen without standard libraries. Any problem with my code? How do I do it then? – Panther Coder May 20 '16 at 18:48
  • You should ask that as a new question . I now know you are using realmode, and using _GCC.. _GCC_ 's code is not quite 16-bit (the code makes stack operations 32-bit wide, and adds address size prefixes where necessary to instructions) . The code will only run on an 80386+ (not an 80286, 8086) or an 386+ emulator in real mode. This may be acceptable to you but is something that must be said. You'd probably need to write the screen update code using assembly code or making it inline. – Michael Petch May 20 '16 at 18:59
  • And you'd do it the same way we did it in the old days. Save _ES_ segment register, set _ES_ segment to 0xb800, use `mov` with an _ES_ segment override to the offset of your choice and then restore _ES_ to its original value. There is another way if your 80386 system is known to be in unreal mode that is more efficient. – Michael Petch May 20 '16 at 19:03
  • I have opened a new thread at http://stackoverflow.com/questions/37354717/how-to-display-text-to-display-areascreen-without-using-library-functions-usin . Kindly elaborate it therein. Thanks. @Michael Petch – Panther Coder May 20 '16 at 19:46
  • I'm curious if my answer at least resolved your linker problem and generated a file called `kernel.bin` for you? – Michael Petch May 20 '16 at 20:11
  • Yes it generated a binary file – Panther Coder May 20 '16 at 20:17

2 Answers2

4

Your Windows version of LD likely doesn't support anything more than windows PE types. One way around this is to output to PE and then use objcopy to convert from the PE file to binary.

For this to work you will have to rename main to _main. With -ffreestanding GCC will emit an object without the Windows ABI convention of prepending a leading underscore to non-static functions. We'll be using your LD to output a Windows PE file first and it will complain about __main entry point not being defined. To get around this you rename main to _main so the linker doesn't complain.

Use these instructions for generating the kernel binary:

gcc -ffreestanding -c -m16 kernel.c -o kernel.o
ld -Ttext 0x10000 -o kernel.pe kernel.o
objcopy -O binary kernel.pe kernel.bin

The LD command outputs to a file called kernel.pe. objcopy converts kernel.pe to binary with -O binary outputting to kernel.bin

Michael Petch
  • 46,082
  • 8
  • 107
  • 198
1

This means that ld itself is not configured at its compile time to support output formats other than PE, Portable Executable - the native Windows executable file format.

Find the one that supports or build it yourself.

Serge
  • 6,088
  • 17
  • 27