Page 1 of 2
Native windows compiler which can output flat binaries?
Posted: Sat Jan 12, 2008 7:30 pm
by lollynoob
Hello; I've been working on my hobby OS for a while now, in pure x86 assembly, but I see quite a few advantages in switching the majority of code to C (ease of development, possible portability, greater readability, etc.).
However, it seems I'm out of luck as far as compilers (that do what I need) go. What I'm looking for is a C compiler that can output a simple 32-bit flat (note: not ELF) binary; along with this, I'd like it to be able to be run natively in Windows (for purely aesthetic reasons; I'd just rather not have to bother with Cygwin).
Does anyone have any recommendations, or should I just bite the bullet and get used to Cygwin?
Also, a note for those about to pelt me with comments about this; it's not the Unix environment that I find ugly about Cygwin, it's the fact that it's an emulated Unix environment running on another system.

Posted: Sat Jan 12, 2008 7:41 pm
by ucosty
I have no idea if TinyCC fits
http://fabrice.bellard.free.fr/tcc/
thats the only one I can think of at the moment.
edit: there's also LCC, but I also don't know if it will do what you want
http://www.cs.princeton.edu/software/lcc/
Posted: Sun Jan 13, 2008 5:41 am
by Craze Frog
Almost any C compiler will work as long as your linker can output flat binary files.
Posted: Sun Jan 13, 2008 6:20 am
by thepowersgang
You can use GCC from
MinGW and use a linker script.
Or you could use the DJGPP binutils from
osdever.net
Posted: Sun Jan 13, 2008 6:26 am
by AndrewAPrice
If you don't like Cygwin then you could try Windows Services for Unix includes GCC 3.5 which can output to flat binary. It's not an "emulated Unix environment" since:
- Windows is fully POSIX compatible.
- GCC isn't a 'Unix-specific' program, but a program just like any other that you can compile and run natively on any platform.
Posted: Sun Jan 13, 2008 1:48 pm
by lollynoob
Thanks a bunch, guys; I've found DJGPP seems to suit my needs (it can compile to a flat binary easily), however, I've run into a problem. I've not tested it with by bootloader yet, but a simple test program I compiled (a main() function with no actual code inside) somehow ended up at 7KB or so, which seems really odd. I'm thinking DJGPP linked some runtime code into there (perhaps DPMI startup code?).
So, sorry to get off of the original topic, but does anyone know how to get just the code I write compiled into a flat binary?
Edit: I just recompiled and ran ld with -nostdlib, and that cut the size in half; however, that's still over 3KB for no code, which seems a little weird. Pardon my newbie-ness, but I've got no idea what other options are available for getting rid of unused code (or whatever else is taking up 3KB).
Posted: Sun Jan 13, 2008 2:42 pm
by bewing
I'm afraid you just ran into the one real problem with all current C compilers. Not one of them will create an output file as tiny as it should be.
If you want a tiny output file, stick with pure asm. Once your OS is booted, and your space constraints are gone, write everything else in C. It will only be 5 or 6 times bigger than it needs to be.
One thing you can do, however, is to compile in C, disassemble the object file (or output binary) into assembler, and edit the hell out of it until it is nicer. I make my living optimizing other people's drivers into assembler, and that is how I do it when I'm just doing a quickie job. But that way, the C compiler figures out all the registers for you, and that's one of the parts that takes the longest when you are coding asm by hand.
Posted: Sun Jan 13, 2008 4:35 pm
by lollynoob
Well darn; I might just stick with assembly then, at least for my kernel--I'm just wondering what's taking up all that space (granted, it's not much by today's standards, but I can't stand waste). I guess if things get unbearable in assembly I'll give C another shot and try to ignore the bloat.

Posted: Mon Jan 14, 2008 2:12 am
by Solar
bewing wrote:Once your OS is booted, and your space constraints are gone, write everything else in C. It will only be 5 or 6 times bigger than it needs to be.
Bollocks. Even
if your compiler links in some runtime stuff, that's a one-time cost, i.e. the "penalty" for using C gets smaller the more code you have. The size factor between ASM and (functionally equivalent) C code is nowhere near x2, let alone x5 or x6.
I'd suggest you compile your C code to object format (instead of plain binary), disassemble it, and
find out what's taking up the space.
Posted: Mon Jan 14, 2008 4:35 am
by 2dum2code
I am only a few days into working on this type of stuff, but here is how I'm doing it. I suggest biting the bullet. Here is the script I use to compile my bootloader (which is a flat binary):
#/bin/bash
# How to compile Richard's Useless Boot Code
# By Richard Fairthorne
# Use gcc as the assembler since it support macros
# This will automatically run 'gcc' and then 'as' to produce a PE binary
# under windows, or an ELF or a.out under Linux
gcc bootie.S -o bootie.o -c
# link, fixed addresses, assuming .text loads at 0X7C00
# we could probably skip this if 'as' produced fixed addresses
ld -Ttext 0x7C00 -o bootie.linked.o bootie.o
# convert the text section of the (probably) PE binary into a raw binary
objcopy --only-section=.text -O binary -j .text bootie.linked.o bootie.img
# Scratch head and wonder why objcopy pads the text section to the nearest
# octaword with 0x90, and then to the next octaword with 0xffffffff00000000
# Consider reporting it to as a bug
# Optionally, remove the intermediate steps
rm bootie.o bootie.linked.o
# Copy up to 512 bytes onto the boot sector
dd count=1 bs=512 conv=notrunc if=bootie.img of=/cygdrive/c/Users/Richard\ Fairthorne/Documents/bootie/hd10meg.img
As you can tell from my comments, it's been a fun-filled adventure trying to get these tools to do what I want. haha
Posted: Mon Jan 14, 2008 4:40 am
by 2dum2code
Hey two other quick comments:
1. After my little journey above, I noticed.. most of the content of a small object file is not code. Dumping it to a binary removes far more than half of the size in my case.
2. In non-trivial code examples on modern processors, smaller != faster. Optimizing compilers intentionally create larger code.
Posted: Mon Jan 14, 2008 5:04 am
by JamesM
Depending on your LD script, the .text, .data and .bss sections may be page-aligned, which wouldn't increase an ELF (EDIT: so as to not annoy the M$ types: and COM, and PE etc...) file size (because it supports sections) but will increase the size of a pure binary file (as the intervening space must be padded with zeroes).
Posted: Mon Jan 14, 2008 5:14 am
by 2dum2code
JamesM wrote:Depending on your LD script, the .text, .data and .bss sections may be page-aligned [...] the intervening space must be padded with zeroes
If you're responding to my "objcopy" related comments, that thought did run through my head.. or at least the thought that it was somehow alignment related -- but I'm creating the binary from a PE file, and it contains only one section. The idea of intervening space should not apply.
I've never used any of these tools before though, so I'm not quite ready to blame them yet. I'm curious if the result would be the same if I converted to an intermediate format before converting to a raw binary.
- Rich
Posted: Mon Jan 14, 2008 5:57 am
by JamesM
Well, here's a test executable:
Code: Select all
[11:49:41] aubergine: ~/test
$ cat test.c
void _start()
{
int a = 0;
int b = 6 / a;
for(;;);
}
And it produces this output:
Code: Select all
[11:49:15] aubergine: ~/test
$ gcc -o test test.c -nostdlib
[11:49:18] aubergine: ~/test
$ ./test
Floating point exception
[11:49:20] aubergine: ~/test
$ ls -lh test
-rwxr-xr-x 1 jamesmol transitive 731 Jan 14 11:49 test
[11:49:32] aubergine: ~/test
$ objdump -d test
test: file format elf32-i386
Disassembly of section .text:
08048094 <_start>:
8048094: 55 push %ebp
8048095: 89 e5 mov %esp,%ebp
8048097: 83 ec 10 sub $0x10,%esp
804809a: c7 45 f8 00 00 00 00 movl $0x0,0xfffffff8(%ebp)
80480a1: b8 06 00 00 00 mov $0x6,%eax
80480a6: 99 cltd
80480a7: f7 7d f8 idivl 0xfffffff8(%ebp)
80480aa: 89 45 fc mov %eax,0xfffffffc(%ebp)
80480ad: eb fe jmp 80480ad <_start+0x19>
[11:49:41] aubergine: ~/test
$
Not exactly massive, and notice the size: 731 bytes. For an ELF file.
Incidentally, when recompiled as a flat binary...
Code: Select all
[11:56:36] aubergine: ~/test
$ gcc -o test test.c -nostdlib -Wl,--oformat=binary
[11:56:38] aubergine: ~/test
$ ls -lh test
-rwxr-xr-x 1 jamesmol transitive 27 Jan 14 11:56 test
[11:56:41] aubergine: ~/test
$
27 bytes. Not exactly bloated!
Posted: Mon Jan 14, 2008 9:15 am
by mathematician
If you look long and hard enough at the Watcom documentation you might find that their linker has some useful directives. For example:
form elf (output an elf executable)
order clname code offset=0x100000 (load segments with the class 'code' starting at 0x100000)
output raw (produce an executable, and then convert it to flat binary)
For things like the boot sector you can also tell it to produce a DOS COM file after putting an org 7c00h in the source code. (You might have to write a utility to strip off 7c00 worth of null bytes - that seems to depend upon the mood it is in at the time).