Compiling C Code to RISC-V Assembly Language

By default, compilers perform the entire compilation, assembly, and linking process when invoked from the command line. To interrupt the compilation process after translating C code to assembly language, you must pass a flag to the compiler on the command line. In the case of gcc and clang, this flag is -S. The following command illustrates how to translate C code from the file prog.c to assembly language and save the result in the prog.s file.

clang -S prog.c -o prog.s

To test the above command, you can create a text file called prog.c and place the following content:

/* Program that returns the answer to the Ultimate Question of
 * Life, the Universe, and Everything */
int main(void) {
  return 42;
}

The command clang -S prog.c -o prog.s will produce code for the native machine's assembly language, i.e., for the machine running the compiler. If you are running the compiler on a computer with an Intel or AMD processor, this means you will produce assembly language code for the x86 architecture family. Since we are interested in producing code for RISC-V, we need to inform the compiler with special flags. In the case of clang, we will use the flags --target=riscv32, -march=rv32g, and -mabi=ilp32d. These flags configure the compiler to emit code for 32-bit RISC-V. The code below illustrates the compilation of the code from the file prog.c to RISC-V assembly language:

clang --target=riscv32 -march=rv32g -mabi=ilp32d -mno-relax prog.c -S -o prog.s

You can check the contents of the prog.s file (produced by the above command) by opening it in your favorite text editor. It is a text file and contains the same program you wrote in C, but transcribed into assembly language for the RISC-V RV32 architecture. Note that assembly language refers to instructions (add, mv, etc.) and other elements specific to each type of processor and, consequently, is dependent on the processor's interface.

Note: In case your system runs on x86 or ARM based processors, if you compare the code produced for the native architecture and the code produced for RISC-V RV32, you will notice that the instructions generated by the compiler are quite different.