How to compile an assembly file to a raw binary (like DOS .com) format with GNU assembler (as)? [duplicate]
Asked Answered
R

3

9

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 :)

Rondelet answered 12/12, 2011 at 22:49 Comment(9)
Maybe you can start by writing your own assembler :) I'm guessing the "290" bytes you're referring to is from the file header: every binary object file has one of these.Tamer
@paulsm4: Yes! 290 bytes header but I dont want any header!Rondelet
@Amir - can't you just use objcopy or segedit or something to copy out the binary parts you care about?Alcaic
@CiroSantilli新疆改造中心996ICU六四事件: should this be closed as a duplicate of How to generate plain binaries like nasm -f bin with the GNU GAS assembler??Praedial
@PeterCordes yes, that is what I said 5 years ago on my previous comment :-)Divorcee
@CiroSantilli新疆改造中心996ICU六四事件: I was asking if that was still accurate, since you have an answer on both questions that you've updated since then.Praedial
@PeterCordes I need to get one of those assembly dupehammers XDDivorcee
@CiroSantilli新疆改造中心996ICU六四事件: Some of your assembly answers seem to be under a 2nd account. Merging them might help.Praedial
@PeterCordes it's OK, I need a "politically amoral" puppet for reasons :-)Divorcee
D
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://mcmap.net/q/14711/-how-does-c-linking-work-in-practice-duplicate

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.

Divorcee answered 26/8, 2015 at 21:32 Comment(0)
S
0

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

Soakage answered 12/12, 2011 at 23:36 Comment(5)
But NASM can't compile the assembly output of gcc (See gcc -S my_os.c -o my_os.asm -masm=intel)Rondelet
On the other hand, gcc doesn't generate 16-bit code, which you need because your boot sector starts executing in 16-bit mode. All pointer/address manipulations in C code compiled for 32-bit mode will be wrong in 16-bit mode.Soakage
Downvoter, be more constructive.Soakage
@alex the poster is obviously using the GAS assembler, not NASM. So your answer is not really an answer at all.Stereochrome
@Hawken: IIRC, (g)as does not produce flat/raw binaries. Do we want an impossible solution?Soakage
C
0
org 100h
nop
nop

You can use fasm to compile:

fasm yourcode.asm targetfilename.com
Cancellation answered 22/6, 2018 at 17:57 Comment(3)
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.Praedial
I see, but I don't understand why must be use another compiler when fasm produce the correct result.Cancellation
This was already debated in comments 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.Praedial

© 2022 - 2024 — McMap. All rights reserved.