# Binutils: Adding LD Parameters for RISC-V This artical is about how to add ld parameters in binutils. ## Related Files * *ld/emultempl/elf.em*: this is the general template of the emitted C file * *ld/emultempl/riscvelf.em*: RISC-V specific script to emit C file **NOTE** The em means "emit" (maybe ...) ## ld/emultempl/elf.em *ld/emultempl/elf.em* is the top level of emit template. It reads the content of other *.em* fils and emit the final C file. ## ld/emultempl/riscvelf.em If we build binutils for RISC-V target, *<build_dir>/ld/eelf\*briscv.c* files are generated from this script. In `riscvelf.em`, one can use some syntax to specify what to emit. ### Inserting lines to the emitted C file ``` shell fragment <<EOF ... <content you want to add to the emitted C file. ... EOF ``` This is known as the ["here-document"](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_07_04) syntax, that "redirection of subsequent lines read by the shell to the input of a command". :::info ℹ️ **NOTE** The `fragment()` command is defined in *ld/genscrba.sh*: ``` fragment() { if [ ${BASH_VERSINFO[3]} -ge 3 ]; then local lineno=$[${BASH_LINENO[0]} + 1] echo >> e${EMULATION_NAME}.c "#line $lineno \"$em_script\"" fi cat >> e${EMULATION_NAME}.c } ``` ::: ### Predefined shell variables To add a new option, we need to set several shell variables in the *.em* file. * `$PARSE_AND_LIST_PROLOGUE`: defines enums that will be refer to this option. * `$PARSE_AND_LIST_LONGOPTS`: defines the ld option properties, like option name, type, and enum refering to the options. * `$PARSE_AND_LIST_OPTIONS`: a small piece of C code that prints the option help message. * `$PARSE_AND_LIST_ARGS_CASES`: a small piece of `case` condition to set variables to store pares result. ## Example: Adding `--relax-gp` Option Here is the reference commit: https://github.com/bminor/binutils-gdb/commit/50980ba351856dff75bb0743bfca62f4c3ab19ff At the beginning, of *riscvelf.em*, it inserts some include statement and defined some variables: ``` c fragment <<EOF #include "ldmain.h" #include "ldctor.h" #include "elf/riscv.h" #include "elfxx-riscv.h" static struct riscv_elf_params params = { .relax_gp = 1 }; EOF ``` Note that the `riscv_elf_params` is defined in *struct elfxx-riscv.h*. Then it defines the shell script variables we mentioned above. `$PARSE_AND_LIST_PROLOGUE` to add new enum: ``` # Define some shell vars to insert bits of code into the standard elf # parse_args and list_options functions. */ PARSE_AND_LIST_PROLOGUE=${PARSE_AND_LIST_PROLOGUE}' enum risccv_opt { OPTION_RELAX_GP = 321, OPTION_NO_RELAX_GP, }; ' ``` `$PARSE_AND_LIST_LONGOPTS` to set parameter properties: ``` PARSE_AND_LIST_LONGOPTS=${PARSE_AND_LIST_LONGOPTS}' { "relax-gp", no_argument, NULL, OPTION_RELAX_GP }, { "no-relax-gp", no_argument, NULL, OPTION_NO_RELAX_GP }, ' ``` `$PARSE_AND_LIST_OPTIONS` to print help message: ``` PARSE_AND_LIST_OPTIONS=${PARSE_AND_LIST_OPTIONS}' fprintf (file, _(" --relax-gp Perform GP relaxation\n")); fprintf (file, _(" --no-relax-gp Don'\''t perform GP relaxation\n")); ' ``` `$PARSE_AND_LIST_ARGS_CASES` to add new switch-case for option parser: ``` PARSE_AND_LIST_ARGS_CASES=${PARSE_AND_LIST_ARGS_CASES}' case OPTION_RELAX_GP: params.relax_gp = 1; break; case OPTION_NO_RELAX_GP: params.relax_gp = 0; break; ' ```