Page 1 of 3

Binary files and GCC

Posted: Sat Nov 03, 2007 5:34 am
by XCHG
Suppose I have a C program like this:

Code: Select all

void SomeProcedure (void){
  return;
}

int __attribute__((stdcall)) SomeFunction (int Param1){
  return(Param1);
}
I want to make GCC produce a simple Object file for me where [SomeProcedure] has the entry at the 0x00000000 offset of the object file so that I can simply call it. When I compile the project with this command line to get the Assembly output file:

Code: Select all

GCC -S -O3 -masm=intel c1.c -o c1.asm
I get a bunch of code that are unnecessarily put into my program. Like stack frames for procedures that do not have local variables/parameters.

My question is: is there a way to make GCC produce a simple OBJ file like the output of NASM (NASM -f bin)?

Posted: Sat Nov 03, 2007 7:03 am
by Brynet-Inc
The output file is still going to be ELF, unless you have a custom binutils setup..

As for the other thing.. you could try -fomit-frame-pointer.

Perhaps you should read GCC's documentation?

Re: Binary files and GCC

Posted: Sat Nov 03, 2007 7:09 am
by bluecode
XCHG wrote:I get a bunch of code that are unnecessarily put into my program. Like stack frames for procedures that do not have local variables/parameters.
These stackframes are not unnecessary. They are for debugging purpose. You can turn that of via -fomit-frame-pointer.
My question is: is there a way to make GCC produce a simple OBJ file like the output of NASM (NASM -f bin)?
That would normally be the job of a linker. You have to pass some of LDs options as a command-line argument for GCC (I don't know how that works though).
Or you could compile/assemble your files independent into object code and then link them together explicitly with LD.
I want to make GCC produce a simple Object file for me where [SomeProcedure] has the entry at the 0x00000000 offset of the object file so that I can simply call it.
I don't really understand that... Why not just declare SomeProcedure extern in your assembler file and then do "call SomeProcedure" (be carefull, perhaps the name got mangled, nm/objdump will tell ya)?

Posted: Sun Nov 04, 2007 4:07 am
by XCHG
Brynet-Inc wrote: As for the other thing.. you could try -fomit-frame-pointer.

Perhaps you should read GCC's documentation?
Thanks.

bluecode wrote:That would normally be the job of a linker. You have to pass some of LDs options as a command-line argument for GCC (I don't know how that works though).
Or you could compile/assemble your files independent into object code and then link them together explicitly with LD.
So I will write the program and then compile it into an object file then link it together with my other object files and produce the final flat binary file eh?

bluecode wrote:I don't really understand that... Why not just declare SomeProcedure extern in your assembler file and then do "call SomeProcedure" (be carefull, perhaps the name got mangled, nm/objdump will tell ya)?
For example, in NASM; when I write a procedure/function at the top of the source code, I will be sure that the first instruction in that procedure is the first assembled instruction in the binary file. So if I load that file into memory in my OS and CALL the offset 0x00000000 in that file, I would know that the first procedure is called. Is that possible in C or should I create jump tables and etc?

The reason I want to do this is to, for example, write a device driver for mice and then load that dynamically in my Operating System. I want the "init()" method of any device driver to start at the first instruction in the flat binary file.

Posted: Sun Nov 04, 2007 4:41 am
by bluecode
XCHG wrote:So I will write the program and then compile it into an object file then link it together with my other object files and produce the final flat binary file eh?
right.
XCHG wrote:So if I load that file into memory in my OS and CALL the offset 0x00000000 in that file, I would know that the first procedure is called. Is that possible in C or should I create jump tables and etc?
iirc you can put a function into a different section via __attribute__((something_here)). Then you could specify in the linkerscript, that this section goes first in the final binary. Or of course you could use a jump-table.

Posted: Sun Nov 04, 2007 4:47 am
by XCHG
Thank you [bluecode]. I'm on it right now. I will post back here if something goes wrong.

Posted: Sun Nov 04, 2007 5:23 am
by XCHG
Alright, I read GCC's documentation and found some useful command line switches. This is my source file:

Code: Select all

void __attribute__((stdcall)) WriteX (void){
  char* VideoPointer = (void*) 0x000B8000;
  *VideoPointer = 'x';
  return;
}
I compile this program with this command:

Code: Select all

gcc -O3 -fomit-frame-pointer -finline-functions -nostdinc -c c1.c -o c1.o
Then I will get the "c1.o" file. I have this linker script:

Code: Select all

OUTPUT_FORMAT("binary")
ENTRY(start)
phys = 0x00100000;
SECTIONS
{
  .text phys : AT(phys) {
    code = .;
    *(.text)
    *(.rodata)
    . = ALIGN(4096);
  }
  .data : AT(phys + (data - code))
  {
    data = .;
    *(.data)
    . = ALIGN(4096);
  }
  .bss : AT(phys + (bss - code))
  {
    bss = .;
    *(.bss)
    . = ALIGN(4096);
  }
  end = .;
}
Then when I try to link the "c1.o" and make a flat binary file, I get this error:

Code: Select all

C:\c>ld -T link.ld c1.o -o c1.bin
ld: cannot perform PE operations on non PE output file 'c1.bin'.
Could anybody tell me what I am doing wrong, please?

Posted: Sun Nov 04, 2007 5:46 am
by Brynet-Inc
There are hundreds of posts on the forum with that specific error...

You're using Cygwin's port of GCC/binutils, which is highly modified for that platform. (And emits PE files..)

It's time to start considering an ELF Cross Compiler.

Good luck..

Posted: Sun Nov 04, 2007 6:09 am
by XCHG
I was using MinGW :shock: I am downloading Cygwin now. Why should this process be so complicated? Is it too hard for the compiler to give me a simple binary output?

Posted: Sun Nov 04, 2007 7:27 am
by XCHG
Okay I don't think I have any more time to play with this. Could anyone tell me straight away what compiler options and switches you use to compile this program into a flat binary file?

Code: Select all

void __attribute__((stdcall)) WriteX (void){
  char* VideoPointer = (void*) 0x000B8000;
  *VideoPointer = 'x';
  return;
}
Thanks guys.

Posted: Sun Nov 04, 2007 8:39 am
by frank
I would use. This is with a cygwin gcc cross compiler targeting ELF.

Code: Select all

gcc -fno-builtin -nostdlib -ffreestanding -o file.o file.c
ld file.o --oformat binary -T ldscr.ld - o file.bin

Posted: Sun Nov 04, 2007 11:53 pm
by os64dev
What i do with respect to the binary file. I compile my program to an elf executable and use objcopy to convert it to binary. I think that could even be done with PE executables. I do use a cross compiler but that should be no different then a regular compiler.

Posted: Tue Nov 06, 2007 8:38 am
by XCHG
Thanks guys. One big problem. How am I actually supposed to set up my C development environment? I have downloaded the Cygwin setup.exe file and it is unstructured with millions of packages in front of me. I searched for GCC in those and I couldn't find the. God these are some of the reasons I never liked to use C for OS Development :lol: So could someone "give me a hand" with this. Suppose I don't have GCC/Cygwin/MinGW and etc. What should I download now? From where? Why is Cygwin is using a list-view inaccurately? lol

Posted: Tue Nov 06, 2007 8:51 am
by XCHG
Alright, never mind. I found a way to download Cygwin's GCC package and etc. I will ask more questions here (if any). Thanks guys.

Posted: Tue Nov 06, 2007 8:56 am
by XCHG
Wow I'm impressed. Cygwin sucks too :lol:

Code: Select all

C:\c>gcc -fno-builtin -nostdlib -ffreestanding -o c1.o c1.c

C:\c>ld c1.o --oformat binary -T link.ld -o c1.bin
ld: cannot perform PE operations on non PE output file 'c1.bin'.
Or is there something that I am doing wrong? By the way, I just looked at the output object file that GCC produced and it is clearly a Win32 PE file.