Hi,
The whole process goes like this:
1. When you compile and link your program, you get an executable file that packs your code and data into a specific format. ELF and COFF are only two of these formats. ELF is a little more complex and at the same time the most flexible and it is used mostly in the UN*X world, COFF is very powerful too, a little bit easier to work with (at least that's what I heard) and Micro$oft used a derivate of the format for the Windoze exe files. However, none of them is generally suitable to load directly into a microcontroller, unless you are running an OS on it. So generally after this you must get to the second step.
2. After you get your executable file you must upload it into the microcontroller. This step involves copying the sections you need from the ELF file (generally all code and data sections) into a format more suitable for uploading. HEX and SRecord are two of these formats. These are text files that augment the data with address and checksum information and split it into small chunks (lines). In this way the program is easily uploadable from any terminal program. Again HEX and SRecord are quite similar in functionality; some versions of SRecord contains more record types. You can get a tool that converts between the HEX format (for example SRecord, hxxp://ftp.tuwien.ac.at/softeng/Aegis/srecord.html)
HTH.