<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/83111>83111</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
RISC-V ABI break: x7/t2 register is used to pass the 9th argument to a function in certain cases
</td>
</tr>
<tr>
<th>Labels</th>
<td>
new issue
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
euspectre
</td>
</tr>
</table>
<pre>
According to the RISC-V ABI, the first 8 integer arguments of a function are passed in registers a0-a7, the 9th and subsequent ones go on stack. It seems, clang does not always conform to that.
While investigating a crash in the Linux kernel built with clang 17.0.6, I found that x7/t2 register rather than the stack was used to pass the 9th argument, `mpri`, to [__find_rr_leaf() function from net/ipv6/route.c](https://elixir.bootlin.com/linux/v6.8-rc4/source/net/ipv6/route.c#L786).
Here is a reduced and simplified version of the preprocessed net/ipv6/route.c that demonstrates the issue:
[test-arg9.c](https://github.com/llvm/llvm-project/files/14415823/test-arg9.c.txt)
It can be compiled as follows (the options were extracted from the kernel build):
```
clang --target=riscv64-linux-gnu -fintegrated-as \
-Werror=unknown-warning-option -Werror=ignored-optimization-argument -Werror=option-ignored \
-Werror=unused-command-line-argument \
-std=gnu11 -fshort-wchar -funsigned-char -fno-common -fno-PIE \
-fno-strict-aliasing -mabi=lp64 -march=rv64imac_zihintpause \
-mno-save-restore -mcmodel=medany \
-fno-asynchronous-unwind-tables -fno-unwind-tables -fno-delete-null-pointer-checks \
-O2 \
-fstack-protector-strong -fno-omit-frame-pointer -fno-optimize-sibling-calls \
-ftrivial-auto-var-init=zero \
-falign-functions=4 -fpatchable-function-entry=12 \
-fstrict-flex-arrays=3 -fno-strict-overflow -fno-stack-check \
-Wall -Wundef -Werror=implicit-function-declaration \
-Werror=implicit-int -Werror=return-type -Werror=strict-prototypes \
-Wno-format-security -Wno-trigraphs -Wno-frame-address -Wno-address-of-packed-member \
-Wmissing-declarations -Wmissing-prototypes \
-Wframe-larger-than=2048 -Wno-gnu -Wno-unused-but-set-variable -Wno-unused-const-variable \
-Wvla -Wno-pointer-sign -Wcast-function-type -Wimplicit-fallthrough \
-Werror=date-time -Werror=incompatible-pointer-types -Wenum-conversion \
-Wno-unused-but-set-variable -Wno-unused-const-variable -Wno-pointer-to-enum-cast \
-Wno-tautological-constant-out-of-range-compare -Wno-unaligned-access -Wno-cast-function-type-strict \
-Wno-missing-field-initializers -Wno-type-limits -Wno-shift-negative-value -Wno-initializer-overrides \
-Wno-sign-compare -Wno-unused-value -Wno-parentheses-equality -Wno-self-assign \
-g -c -o test-arg9.o test-arg9.c
```
clang: version 17.0.6 (https://github.com/llvm/llvm-project.git 6009708b4367171ccdbf4b5905cb6a803753fe18)
Target: riscv64-unknown-linux-gnu
A disassembly of test-arg9.o:
[test-arg9.disasm](https://github.com/llvm/llvm-project/files/14415827/test-arg9.disasm.txt)
Here are the portions of `__find_rr_leaf()` (callee) and `fib6_table_lookup()` (caller) where t2 is used to pass the 9th argument to the function:
```
fib6_table_lookup():
...
00000000000000c4 <.LBB0_9>:
c4: 00ccab83 lw s7,12(s9)
c8: f8043423 sd zero,-120(s0)
cc: f9b42223 sw s11,-124(s0)
d0: f8840713 addi a4,s0,-120
d4: f8340893 addi a7,s0,-125
d8: f8440393 addi t2,s0,-124 // <<< here
dc: 8566 mv a0,s9
de: 4581 li a1,0
e0: 865e mv a2,s7
e2: 86da mv a3,s6
e4: 87ce mv a5,s3
e6: 884a mv a6,s2
e8: 00000097 auipc ra,0x0
e8: R_RISCV_CALL_PLT __find_rr_leaf
e8: R_RISCV_RELAX *ABS*
ec: 000080e7 jalr ra # e8 <.LBB0_9+0x24>
...
__find_rr_leaf():
...
1e2: 891e mv s2,t2
...
00000000000002b2 <.LBB1_16>:
2b2: 00092503 lw a0,0(s2) // <<< "if (m > *mpri)" in find_match()
2b6: 01455063 bge a0,s4,2b6 <.LBB1_16+0x4>
2b6: R_RISCV_BRANCH .LBB1_4
2ba: 0d05 addi s10,s10,1
2bc: 001d3513 seqz a0,s10
2c0: f4843583 ld a1,-184(s0)
2c4: 00a58023 sb a0,0(a1)
2c8: 01492023 sw s4,0(s2) // <<< "*mpri = m;" in find_match()
2cc: a001 j 2cc <.LBB1_16+0x1a>
2cc: R_RISCV_RVC_JUMP .LBB1_3
...
```
This looks like a RISC-V ABI break.
Ftrace, for example, relies on the fact that the temporary registers like t0-t2 can be safely clobbered at the beginning of the function. So, if dynamic Ftrace is enabled for __find_rr_leaf() in the kernel, t2 could contain anything when the function tries dereferencing its 9th argument, `mpri`, hence the kernel crashes.
I do not think this issue has security implications, so, I am reporting it here.
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJysWN1v47gR_2uYF4KGRMm29JCHfGxwW2zbw9710reAokYWLxTpIykn2b--GOrDUuLd3hU1DCcSOZ-_meFwhPfqYACuyfaWbO-vRB9a666h90eQwcFVZeu36xsprauVOdBgaWiBfv38yx37jd7cfib8Lr5plPOBFlSZAAdwVLhD34EJntqGCtr0RgZlDRUO6FF4DzVVhjo4KB_AeSoSJvYTszK0VJia-r7y8EcPJlBrwNODpdZQH4R83tDPgXqAziOR1MIcaG3BU2MDFfpFvHkqrWms6walRdiQ5J4kN8PvY6s0UGVO4IM6iIDGCSqd8C0qhlp8UaZ_pc_gDGha9UoH-qJCOwpL95tks0Phn2lje1NHGfR1T_hD4LNl1InQgsPFgWvUnr4IT3t0QrDRHWezR78hY7JLuqNTZJdEx1hKtrdPT40y9ZNzTxpEQ3hBeHn2buNsRw0Ewh_U8bQj_MHZPsBGku094UUbwtGT7IbwB8IfQKtX5TaVtUErs5G2I_xBo9GEP5x2m4I5mRP-4G3vJBD-cJExz77six3h5cq9P4EDqjwV1EHdS6gHPFV31KpRUNMTOI8a2yaafnRwdFZCDIxLcgbv1tBZ44MTAQaXKe97QIsG2dvbAD4w4Q7lZZsPKrR9NdmqT9MfdnT2d5Aot1EaPOEPaZ6n24JniOeZ6Sa8BsLLpa2fA5XC0AqotN1RaTTW08ZqbV88JbxARe0RAfL0BR0Dr8EJGaAeAMP1RZjVyH82aZeM3_g4xB5jQbgDBJLdO-XlaZeziBs7mJ6yJuYg-qhmwlOyvRtoKXsE56wj2X1vno19MexFOKPMgQ3aLTaog7EO6rjQqW8Cl9kUm4t9AyEbty9krYRhpDNpu06YGjWFM6uFdj7UJLs_mD5NKWt8a11gL7IVjrKmN7FO1Wx8NjbyQ53x_58_f1pywlc-OCUDE1oJj8nNOlEpkt3r4y7HBydbdN9pl6tOyKdvqlUmHEXvYcmpQ07iBMyBD9YBZZ3sbA2aZPcd1MK8rWxGwcK_Gdk6a2zvWW9elKlZEJUGP6xfeFWDhgDM9Fqzo0X4HJMtyGe_4v5PvjIyVhIM3AAyWIcWWzQUOdpOBdY40cHEcHw_4AnMq0oj8lJovZbSBKdOSmgm-mDZSTimjMJQ-wbOrncKrQ6GTdXHk-w-p6w5iiBbtG5eYWCCeyPZfcrXDEaQGg2vTDgn3pBHtgLQnsA12r5ML9Hm6Jt1sAmtKXvsTQ3NMoyx3kh0xaRJDVILF-P5crTOJGoV6A5C7wwLb0dYvB11RAwsLq09-WgswwNIBOZB9k6Ft-FlcOrgxLH1456Ik6hrB358NT4w27CjkM9Qsw66CtwqmzvlMbSXNvnF6-9pNYjTWEEcw3OJZPc8yYtBciwhjzFOY9pWPWofMBAUgrpalFiNz0tL5U5aDFungMYEpuxRCr-AY_TnGSehdWid7Q_txcJViwAsqG4JgjJYd0VQGHKTtMFu9gim71DN6bxZMv3fjFwZFSwbJAgf3vMOmEDaHpQUemAiTGC2D4iqE-YALCruZnExn7BqSzlHwkd_jZnxIdQm3BsFuo5Jq4RW37C7GvRBWq06FcYXvlVNYAaw_TkBOwndj6osiGMCOlWDf28fAvreguiwBSNcM6EFD57BH73Qcw540A0b2s-VJQfKJGWWns_c5f_y4qm4OBtJdjP3FkOLRv9yE7A5qEB3SVLuk6LKs90-3adS1lWTV9sy2cpqJ4ok22-zBtJibgZ-HY_kGzqdydMpO5_NS21vaK08NsJdpd9iG3Q2-HJDE_d3_5-uZr_qagbOF1qb2MYhvLFHs24oMbbB1vRSJ0p2CbobDxUA7Eyx6yO7pFHV7imeeE_a2uf--HG7w-0vLQoMHFvHH7bH00VkSoyzxy7Fx_fET0Sbzdi8JquPzCnJ7jZfbm-Tp5Jkn-b9lMo8PpRJIqWoiozOH5KU-oUkpcfbTMoJL3w5e5VSWQyETZHkWc4z3O9rkpR4uhJ-x1KeIE2ypJEjTVnlnPO1MB-FpelAm7-jrZNJXJEn-3RNKupa4Z-c8DskGoSPQut8oszypCizJcF-QbCdCWbL8jzJyouiAl9Q5iQph_hFNw9figEwcxztLra7HX33IUnZnZAxMvOzq-rhMlDm2yKNUER90TmzYTC6pNht4btco577mYRPJLU478lwz27eM_qr2Mvvs90iSTaT7EaSIl-wxTul5_OeYgo0_JT76MxeHSVJSifQrte5CJbDN5LQr094Sf_t6e7my5enn7_8SpLyXcb-iOrrpy83_4743Nzc_kL4HPggz_oUCexXRv4utIt6UcIzCsUyffht8spzzKJ1yg2_F4vJh_Sk6YxEmcLsMo9oBf6jXOYVn5RJn9LdKpl5xWebSr5NsjmHY3DFdOQxpT6GK-FcNVjDOkqyT5Twm3hj5yXhnCpDo1UdNsSjTZPIEfokzbfbZLdOluoAc2RjbvJqt1IeXXn25IzgwHSG8PbrzT_ufiJJOdDls2gxiq6T7YVAHTPVp1F8_E1n0hn8tM6276qJhz--zWqnU7pxOVWgvMizbTE4t56ykqXF-5LFz7VVbIvkfbmrlrggjzNdMfu05B_oYpnM_wSeI4aUZPe0I9ntf0FyKs4iSdIL7vwdgZHyA36puABg5HXOwd_unv72r7__PEOYvU-dS13Qr63yFE85T7V6BioWwzpaORDPq8R7CE5IIPyONtZReBXdUcdHB1qBp3aYWjVChmEEg08BuqN1wr0tBnhRWEhY4NM0xIsG9BuV2lYVOKjpSF3BQRmDd_Jx-DMd4hv6Cx6BVDW0fjOiU5IO6mE7AAbP7zqqeXEINk7thkFKHJhxKm2vayqtCUIZKsxbaFHuSwtmJZkGh8bW4KABB0biLuyTfzySa8FIWI5v4vwQ_MrDn2lt41QSZT_jrx_GVrQVns4Xw-EKNFzikLe3w2xRdNRBbL2iSvGA3FzV11ldZqW4gut0n5QJT_I9v2qvqwyyPN3v5bYudnlRN_tqn-U7sU_zcp_u8it1zROeJ5zvk_02z_hm1wDPiow3BeSFlDnJE-iE0htsIDfWHa6istdFlqbplRYVaB-nxZwbeBkHcJyT7f2Vu45NZ9UfPMkTrXzwZy5BBQ3X72MR4_3DyPTPNH-LkbIyVIKLCEvhwV_1Tl__5QY5GoIdcjT0PwEAAP__bm73BA">