views:

97

answers:

2

More specifically, I would like to produce a file that I can load into memory (for example with mmap) and then jump to the start of that memory to run the code. Ideally, I'd like the option of either making the code relocatable (which might be inefficient) or specifying an explicit address that the code expects to be loaded at (which is a pain), but either one would probably work fine on its own.

+3  A: 

You can do this but you will need to go through the object file format. In particular, the objcopy command can transform an executable file to a "flat" binary file (depending on your target platform). Perhaps something like this:

gcc -o test test.c
objcopy -O binary test test.bin

See man objcopy on your platform for more details.

Greg Hewgill
+1, I knew there was something that did this. Do you know whether I need to load this at a specific address?
David X
Yes you will. It will be the address that the linker was told to link at. Note that you don't normally see the linker's control file, so you may not know where that is....
RBerteig
Where would I find the control file?
David X
@David X: check ld manual or google for ld linker scripts.
snemarch
Try `ld --verbose` or to make sure your seeing the name of the real one, `gcc -Wl,--verbose`. You'll need to search through the verbose stuff a bit ;-). I've added a link to the relevant bit of the ld manual in my answer.
RBerteig
+2  A: 

You want to know about the utility objcopy, which is usually available along with GCC. It is a component of the binutils package of tools, the most visible member of which is the linker, ld.

The process is that you compile your source file(s) and link them generally as usual. That gives you a finished executable in elf (or another relocatable platform-dependent binary) format. You then use objcopy to transform the executable to a flat binary image.

This is most useful for preparing code to be run from ROM, where you would want to make sure you are using a suitable C runtime library for your target platform, and likely need to customize the linker script file as well as provide your own C runtime startup code.

If your goal is to get something that is sort of like a .so file, to be loaded into an existing process, then be aware that some of the work of the shared library loader is to actually finish linking so that symbols in the .so file that refer to addresses in the main executable (or other .so files) get resolved at load time. Using objcopy won't do that, and so it might be difficult for functions loaded this way to properly use your existing C runtime library and objects it maintains such as open files.

Regardless of your goals, you are going to need to seize control of the linker in order to locate your binary at a known address. To do that, you will need to craft a linker script. Documentation for the script language is in the binutils manual. You will be primarily interested in the ".text*" sections, and possibly in the ".rodata*" sections if you plan to have any initialized global variables. Actually arranging for that initialization is left as an exercise for the reader.

Overall, this is just the tip of a very large iceberg. I'd suggest spending some time with a cross compiler build to see how these things are used in practice. The AVR and MSP430 communities use GCC, have active participation, and inexpensive (and often even open source) hardware to get started.

RBerteig