Search code examples
cassemblylinkerdosreal-mode

How do I link an object file generated from C code, a static library and a NASM generated object file?


I am working on a program (for real real mode) that is loaded by a bootloader to an address in memory and jumps to it and starts executing the program. The problem is that I have the project separated into two files: a.asm (16bit asm, NASM syntax) and b.c (which i compile with gcc for dos (djgpp)). Also, b.c uses some functions from the allegro library (I have it as a static library, .a).

My question is, how do I compile and link these 3 files together? My first thought was to:

  1. Compile and assemble b.c with gcc (with the -c flag), as a result I get a b.o file
  2. Assemble a.asm with NASM (-fbin or.. ?) and get a.o
  3. Link b.o, a.o and allegro.a to get a pure binary (no .exe headers, no debug information etc.)

I tried the above approach, but at the step 3, the linker throws an error saying that the format of a.o (the object file generated by NASM), is unrecognized, and that may be because either I am not invoking the right flags and options when assembling the file, or..

I would like some guidance on how to approach this problem.

Thanks.


Solution

  • The .o file generated by DJGPP contains 32-bit (i386) code, which cannot be called from 16-bit code directly.

    Under DOS, 32-bit code is typically run by using a DOS extender, which switches to 32-bit protected mode, sets up memory mappings and DOS API translation (i.e. small trampoline functions which switch back to 16-bit real mode when calling the int 21h DOS API). and then loads and calls the 32-bit code.

    Lightweight alternatives of DOS extenders for switching between 16-bit and 32-bit mode:

    • unreal mode with gcc -m16 (.code16gcc). See this answer and other answers more details about gcc -m16.

    • The bootloader of the Syslinux project, which contains 16-bit assembly (NASM), 32-bit assembly (NASM) and 32-bit C (GCC) code, and it switches between them.

    To link 16-bit and 32-bit code together, you can run objcopy -O binary func.o func.bin (32-bit), and then add %incbin "func.bin" to your 16-bit NASM source file. However, this breaks relocations (so you won't be able to use global variables).