Compilation from .c files vs precompiling object files and linking them separately

82 Views Asked by At

I am trying to build a simple hello world program I have written for the riscv64 architecture and run it with qemu. That works as long as I compile specific files as .c files in the main gcc invocation. The specific error is:

main.o: in function `main': 
main.c:(.text+0x8): relocation truncated to fit: R_RISCV_HI20 against `hello'
test.o: in function `test': 
test.c:(.text+0x8): relocation truncated to fit: R_RISCV_HI20 against `hello' 
collect2.exe: error: ld returned 1 exit status

Basically if I compile with:

gcc -march=rv64gc -mabi=lp64d -nostartfiles --machine-cmodel=medany -T linker.ld crt0.o main.c putchar.a test.c -o main.elf

everything works fine. But if I compile main.c and test.c first with

gcc -march=rv64gc -mabi=lp64d -nostartfiles --machine-cmodel=medany -T linker.ld -c main.c test.c

and then

gcc -march=rv64gc -mabi=lp64d -nostartfiles --machine-cmodel=medany -T linker.ld crt0.o main.o putchar.a test.o -o main.elf

I get the relocation errors. I wonder what is the reason for that? I tried compiling the object files as position independent code but with no success. It is worth noting that with the former way with .c files I had the relocation problem before I used the -machine-cmodel=medany option

The code:

main.c:

#include "putchar.h"
// #include "test.h"
static const char *hello = "Hello, World!\n";

void main(){
    // test();
    putchars(hello);
    putchars("Hello, World!\n");
    while(1);
}   

test.c

#include "putchar.h"

static const char *hello = "Hello, World!\n";

void test(){
    putchars(hello);
}

putchar.c

volatile char * const UART = (char*)0x10000000;

void putchars(char *str){
    for(char *i = str; *i != 0; i++) *UART = *i;
}

linker.ld

/* Template linker definition script for riscv64 virtIO machine */

OUTPUT_FORMAT("elf64-littleriscv", "elf64-littleriscv", "elf64-littleriscv")
OUTPUT_ARCH(riscv)

/* Define the entry point */
ENTRY(_start)

/* Define the memory regions */
MEMORY
{
  /* The flash memory region */
  FLASH (rwx) : ORIGIN = 0x20000000, LENGTH = 0x2000000
  /* The RAM memory region */
  RAM (rw) : ORIGIN = 0x80000000, LENGTH = 0x1000000
}

/* Define the output sections */
SECTIONS
{
  /* The text section contains the executable code */
  .text :
  {
    /* Align to page boundary */
    . = ALIGN(0x1000);
    /* Record the start address of this section */
    _stext = .;
    /* Include all input files with .text sections */
    *(.text)
    /* Record the end address of this section */
    _etext = .;
    /* Align to page boundary */
    . = ALIGN(0x1000);
  } > FLASH

  /* The rodata section contains read-only data */
  .rodata :
  {
    /* Align to page boundary */
    . = ALIGN(0x1000);
    /* Record the start address of this section */
    _srodata = .;
    /* Include all input files with .rodata sections */
    *(.rodata)
    *(.srodata)
    /* Record the end address of this section */
    _erodata = .;
    /* Align to page boundary */
    . = ALIGN(0x1000);
  } > FLASH

  /* The data section contains initialized data */
  .data :
  {
    /* Align to page boundary */
    . = ALIGN(0x1000);
    /* Record the start address of this section */
    _sdata = .;
    /* Include all input files with .data sections */
    *(.data)
    *(.sdata)
    /* Record the end address of this section */
    _edata = .;
    /* Align to page boundary */
    . = ALIGN(0x1000);
  } > RAM AT > FLASH

  .fill :
  {
    FILL(0xFFFF);
    . = ORIGIN(FLASH) + LENGTH(FLASH) - 1;
    BYTE(0xAA);
  } > FLASH

  _sdata_load = LOADADDR(.data);

  /* The bss section contains uninitialized data */
  .bss (NOLOAD):
  {
    /* Align to page boundary */
    . = ALIGN(0x1000);
    /* Record the start address of this section */
    _sbss = .;
    /* Include all input files with .bss sections */
    *(.bss)
    /* Record the end address of this section */
    _ebss = .;
    /* Align to page boundary */
    . = ALIGN(0x1000);
  } > RAM

}

Relevant part of the Makefile

CC = riscv64-unknown-elf-gcc
AR = riscv64-unknown-elf-ar

*.o:
    $(CC) -march=rv64gc -mabi=lp64d -nostartfiles --machine-cmodel=medany -misa-spec=20191213 -T linker.ld -c %.c 

crt0.o: crt0.s
    $(CC) -march=rv64gc -mabi=lp64d -nostartfiles --machine-cmodel=medany -misa-spec=20191213 -T linker.ld -c crt0.s

putchar.a: putchar.o
    $(AR) r putchar.a putchar.o

main.elf: putchar.a main.o crt0.o test.o
    $(CC) -march=rv64gc -mabi=lp64d -nostartfiles --machine-cmodel=medany -misa-spec=20191213 -T linker.ld crt0.o main.o putchar.a test.o -o main.elf
1

There are 1 best solutions below

0
droptop On

You should compile main.c and test.c first with

gcc -march=rv64gc -mabi=lp64d -mcmodel=medany -c main.c test.c // or -mcmodel=medlow

before linking, so main.o and test.o contain relocation entries that ld gets to fill during linking.