8

I want to compile this source code in Windows (It just an example):

start:
NOP
NOP

When I compile it with NASM or FASM, output file length is 2 bytes. But when I compile it with GNU assembler (as) the output file length is 292 bytes!

How to compile an assembly file to a raw binary (like DOS .com) format with GNU assembler (as)?


Why I do this?

I want to write my own simple OS, I write my codes with C (without using any C standard libraries even stdio.h or math.h) and convert it to assembly:

gcc -S my_os.c -o my_os.asm -masm=intel

Then, I compile assembly file to a raw binary:

as my_os.asm

Then I rename a.out (output of assembler) to my_os.flp and finally start my OS with VMWare :)

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Amir Saniyan
  • 13,014
  • 20
  • 92
  • 137

3 Answers3

7

ld --oformat binary

For quick and dirty tests you can do:

as -o a.o a.S
ld --oformat binary -o a.out a.o
hd a.out

Gives:

00000000  90 90                                             |..|
00000002

Unfortunately this gives a warning:

ld: warning: cannot find entry symbol _start; defaulting to 0000000000400000

which does not make much sense with binary. It could be silenced with:

.section .text
.globl start
start:
nop
nop

and:

ld -e start --oformat binary -o a.out a.o

or simply with:

ld -e 0 --oformat binary -o a.out a.o

which tells ld that the entry point is not _start but the code at address 0.

It is a shame that neither as nor ld can take input / ouptut from stdin / stdout, so no piping.

Proper boot sector

If you are going to to something more serious, the best method is to generate a clean minimal linker script. linker.ld:

SECTIONS
{
    . = 0x7c00;
    .text :
    {
        *(.*)
        . = 0x1FE;
        SHORT(0xAA55)
    }
}

Here we also place the magic bytes with the linker script.

The linker script is important above all to control the output addresses after relocation. Learn more about relocation at: https://stackoverflow.com/a/30507725/895245

Use it as:

as -o a.o a.S
ld --oformat binary -o a.img -T linker.ld a.o

And then you can boot as:

qemu-system-i386 -hda a.img

Working examples on this repository: https://github.com/cirosantilli/x86-bare-metal-examples/blob/d217b180be4220a0b4a453f31275d38e697a99e0/Makefile

Tested on Binutils 2.24, Ubuntu 14.04.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
0
org 100h
nop
nop

You can use fasm to compile:

fasm yourcode.asm targetfilename.com
sarkiroka
  • 1,485
  • 20
  • 28
  • The question already says "When I compile it with NASM or FASM, output file length is 2 bytes". This isn't an answer to *this* question, which is about GAS. – Peter Cordes Jun 22 '18 at 18:09
  • I see, but I don't understand why must be use another compiler when fasm produce the correct result. – sarkiroka Jun 22 '18 at 18:35
  • This was already [debated in comments](https://stackoverflow.com/questions/8482059/how-to-compile-an-assembly-file-to-a-raw-binary-like-dos-com-format-with-gnu/50993377?noredirect=1#comment10493864_8482487) under the `nasm -f bin` answer (which is the same answer as this one). Presumably they want to use GAS syntax, not NASM or FASM, for whatever reason. Or it seems the question may have come from the mistaken impression that you could usefully use this with `gcc -S` output to make 16-bit code. – Peter Cordes Jun 22 '18 at 18:40
0

Use NASM with the -f bin option to compile your assembly code to a raw binary file.

Alexey Frunze
  • 61,140
  • 12
  • 83
  • 180