> Which gives the following output...
>
> 00000000 <start>:
> 0: 004000ef jal 4 <end>
> 00000004 <end>
> 4: ffdff0ef jal 0 <start>
Two non-obvious things here. First the bytes are being displayed in
"reverse order" because RISC-V uses little-endian for instruction
words. Second RISC-V is a "RELA" target, which means that the 20-bit
immediate fields are *not used* by the linked; the object file
contains a separate "relocation" section which indicates which JAL
points to which label. "objdump -d -r" is what you should use and it
outputs this:
example.o: file format elf32-littleriscv
Disassembly of section .text:
00000000 <start>:
0: 004000ef jal 4 <end>
0: R_RISCV_JAL end
00000004 <end>:
4: ffdff0ef jal 0 <start>
4: R_RISCV_JAL start
> The first 'jal' has correctly indicated that it needs to add 4 to the PC in
> order to jump to the following line, which is address 4. (Note: the odd
> layout of the immediate value for the jal instruction means the actual
> instruction encodes 2 which is then multiplied at the CPU by 2 to get the
> actual offset of 4). The second 'jal' has -2 as the offset. Again, with the
> CPU multiplying by 2 we can -4 as the offset.
(This is all meaningless because of the RELA bit)
> I actually want to generate a raw output file that contains no ELF
> information and is made up of just 8 bytes, the 8 bytes that make up the two
> instructions. I am running directly against a microcontroller and that
> microcontroller is not running an operating system. I want the output to be
> flashed to non-volatile RAM which then executes at reset.
Yep, that's a valid use case
> So I use the following linker command to generate the binary output...
>
> riscv32-unknown-elf-ld --oformat=binary example.o -o example
> But this seems to have lost the relative addressing values because using the
> following command to look at the generate output bytes...
>
> xxd example
>
>
> ...gives the following result...
>
> 00000000: ef00 0000 eff0 ffff
>
>
> Taking into account it is little endian it means that each set of four bytes
> is in reverse order compared to the disassembly seen earlier. We can see the
There's an easier way:
# objdump -bbinary -mriscv:rv32 -D example
example: file format binary
Disassembly of section .data:
00000000 <.data>:
0: ef000000 jal 0x0
4: eff0ffff jal 0x2
(weird that when dumping a binary file objdump uses "big-endian" for
the opcodes.)
> first jump 000000ef has lost its jump offset. The second jump fffff0ef is
> also different from before and after applying twos compliment we get -1,
> which is definitely wrong!
> Any ideas how the jump offsets have been corrupted? Is there some extra
It doesn't work for me either, so you probably found a bug. Suggest
filing it on
https://github.com/riscv/riscv-binutils-gdb/issues/new —
be sure to specify that you are trying to create a binary file
directly from ld.
> option I need to specify to the linker to handle offsets correctly? I cannot
It looks like UCB/SiFive has been using ld with an ELF output followed
by objcopy, which works:
[root@sorear6 tmp]# cat example.lds
OUTPUT_ARCH( "riscv" )
SECTIONS
{
. = 0;
.text : { *(.text) }
}
[root@sorear6 tmp]# ld -m elf32lriscv -T example.lds example.o -o example
[root@sorear6 tmp]# objcopy -S -O binary example example.bin
[root@sorear6 tmp]# objdump -bbinary -mriscv:rv32 -D example.bin
example.bin: file format binary
Disassembly of section .data:
00000000 <.data>:
0: ef004000 jal 0x4
4: eff0dfff jal 0x0
> find anything obvious and as a beginner to Linux and GNU I am stuck.
What you're new to right now is the ELF toolchain and advanced linker
usage, which is fairly arcane even to most GNU/Linux developers. I've
*done this before* and I actually forgot the linker script syntax so I
copied the lds file from riscv-pk and deleted almost everything.
-s