Here’s the few basic steps for the build process that I use all together (It’s also in complete form on my github page).
The three most important tool-chain programs are
objcopy, apart from the assembler (
as) and compiler (
gcc), of course.
Fist, use the
ld program to link all the compiled and assembled objects together, specifying the target’s physical layout in the linker script
.lds file. Using the
-Map option, the generated
.map file contains highly useful information telling exactly where each symbol is placed in memory,
riscv32-unknown-elf-ld start.o foo.o bar.o baz.o ... -T mytarget.lds -o myprog.elf -Map myprog.map
Next, as @disasm points out, you can get the final program listing with all its pneumonics and opcodes, by using the
riscv32-unknown-elf-objdump -D myprog.elf > myprog.lst
Lastly, if desired, use the
objcopy program to translate the .elf to either Intel Hex format, a plain-text ASCII and human-readable representation,
riscv32-unknown-elf-objcopy myprog.elf -O ihex myprog.hex
or a more compact and pure binary format,
riscv32-unknown-elf-objcopy myprog.elf -O binary myprog.bin
This last step is not necessary if your loader/debugger tool accomodates the
.elf file directly. For historical reasons, I’ve always been a fan of Intel Hex.
Both the MAP and the LST files together as an output set have always been highly useful for me.
Note: If you’re using the 64-bit version of the riscv gcc, you can still generate 32-bit binaries – you will need option
-b elf32-littleriscv on the
ld program in the First step above,
riscv64-unknown-elf-ld start.o foo.o bar.o baz.o ... -T mytarget.lds -o myprog.elf -Map myprog.map -b elf32-littleriscv