Skip to content

Incorrect offsets in PCC-relative address calculations when compiling C for CHERIoT #106

@alees24

Description

@alees24

Toolchain issue with auipcc instructions in compiled C.

Commit: 6d22636
(also observed with earlier versions)

The offsets used in the calculation of PCC-relative targets are observed to be incorrect. The offsets appear not to have been adjusted for the fact that the AUIPCC instruction employs an 11-bit shifted constant rather than the RV-standard 12-bit offset. This has been observed to occur when the ensuing instruction is 'clc' (as in the pseudo-op 'cllc'), cincaddrimm or cjalr, as in this demonstration of a simple function call.

In every case that's been studied, the correct target address may be obtained by adding the literal constant from the 'auipcc <>' into the calculated address a second time, i.e. calculating as if that constant were still 12-bit shifted as per the RV standard.
Note: the file cheriot_toolchain.cmake shows the compilation switches being used; since this is our first use of C and CHERI on a large codebase, please do check the options used.

Update: the significant variable in this specific failure is the disabling of linker relaxations, but with more extensive source trees, the same faults occurs even with linker relaxations enabled.

This simple reproduction consists of a simple C/C++ file (test_case.c and test_case.cc; the code is the same) and a contrived assembler file - test_space.S - that ensures the target address is sufficiently far from the call site that auipcc must have a non-zero offset.

Build instructions:

  cmake -B build
  cmake --build build

Output:

  • test_c - ELF file compiled from C source
  • test_cc - ELF file compiled from C++ source

Relevant disassembly from 'test_c':

00200080 <start>:
; start():
  200080: 17 13 00 00  	auipcc	ct1, 1
  200084: 67 00 83 81  	cjr	-2024(ct1)
...
00200898 <start2>:
; start2():
  200898: 6f 00 50 00  	j	0x20109c <start2+0x804>
  20089c: 73 10 00 c0  	unimp
  2008a0: 73 10 00 c0  	unimp

The above disassembly shows the error in test_c but you may also simulate it using the included Verilator build of Sunburst chip:

  ./Vtop_chip_verilator -E build/test_c | more

Output from simulation of test_c (C compilation)

Simulation of Sunburst Chip
===========================

Tracing can be toggled by sending SIGUSR1 to this process:
$ kill -USR1 88228

USBDPI: Monitor output file created at /home/adrianl/toolchain_bug/usb0.log. Works well with tail:
$ tail -f /home/adrianl/toolchain_bug/usb0.log

UART: Created /dev/pts/1 for uart0. Connect to it with any terminal program, e.g.
$ screen /dev/pts/1
UART: Additionally writing all UART output to 'uart0.log'.

Simulation running, end by pressing CTRL-c.
TOP.top_chip_verilator.u_top_chip_system.u_core_ibex.u_ibex_top_tracing.u_ibex_tracer.unnamedblk1: Writing execution trace to trace_core_00000000.log
                  25: Illegal instruction (hart 0) at PC 0x00200098: 0xc0001073
                  33: Illegal instruction (hart 0) at PC 0x00200000: 0x0001145b
                  41: Illegal instruction (hart 0) at PC 0x00200000: 0x0001145b
                  49: Illegal instruction (hart 0) at PC 0x00200000: 0x0001145b

The trace log output is:

Time	Cycle	PC	Insn	Decoded instruction	Register and memory contents
             18	         5	00200080	00001317	CH.auipcc	c6, 0x1	  x6=0x00200880+0x15e3e0000
             22	         7	00200084	81830067	CH.cjalr	c0,-2024(c6)	  x6:0x00200880+0x15e3e0000  x0=0x00000000+0x000000000
             30	        11	00200098	c0001073	-->csrrw	x0,cycle,x0	  x0:0x00000000  x0=0x00000000
             38	        15	00200000	    0000	-->c.unimp	
             46	        19	00200000	    0000	-->c.unimp	
             54	        23	00200000	    0000	-->c.unimp

Compilation with linker relaxations enabled

The corresponding output from the build, where the auipcc/cjalr is replaced with a simple cjal instruction, is fine:

./Vtop_chip_verilator -E build/test_cc | more

Output from simulation of test_c/cc

Simulation of Sunburst Chip
===========================

Tracing can be toggled by sending SIGUSR1 to this process:
$ kill -USR1 88213

USBDPI: Monitor output file created at /home/adrianl/toolchain_bug/usb0.log. Works well with tail:
$ tail -f /home/adrianl/toolchain_bug/usb0.log

UART: Created /dev/pts/1 for uart0. Connect to it with any terminal program, e.g.
$ screen /dev/pts/1
UART: Additionally writing all UART output to 'uart0.log'.

Simulation running, end by pressing CTRL-c.

Time	Cycle	PC	Insn	Decoded instruction	Register and memory contents
             18	         5	00200080	0190006f	CH.cjal	c0,200898	  x0=0x00000000+0x000000000
             26	         9	00200898	0050006f	CH.cjal	c0,20109c	  x0=0x00000000+0x000000000
             34	        13	0020109c	10500073	wfi

Source files for reproducing this issue: source.zip
Simulator binary (x64 Linux): simulator.zip

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions