Hi
Potential GCC bug? - please advise if this is a known issue, if not please inform how to raise an issue on the Gnu toolchain for Morello.
Issue: When defining register variables in a template function, the compiler ignores the directives. Does not happen if not using templates.
Found on: ARM GNU Toolchain for Morello release. Applies to Linux hybrid-cap or Linux pure-cap.- Note: This behaviour does not apply when using clang.
Example Code Snippet
Note: This is based on Arm Morello compartment demo.Intent is to call into a function following C calling convention, with C0...C6 set to passed in arguments:
#include <stdint.h> extern uintcap_t AsUintcap(uint32_t); template <typename Fn> inline void TestCall(uint32_t id, uintcap_t arg0, uintcap_t arg1, uintcap_t arg2, uintcap_t arg3, uintcap_t arg4, uintcap_t arg5, Fn arg6) { register uintcap_t c0 asm("c0") = AsUintcap(id); register uintcap_t c1 asm("c1") = arg0; register uintcap_t c2 asm("c2") = arg1; register uintcap_t c3 asm("c3") = arg2; register uintcap_t c4 asm("c4") = arg3; register uintcap_t c5 asm("c5") = arg4; register uintcap_t c6 asm("c6") = arg5; asm __volatile__("blr %[fn]\n" : : [fn] "C"(arg6), "C"(c0), "C"(c1), "C"(c2), "C"(c3), "C"(c4), "C"(c5), "C"(c6) ); } void DoTestCall(uint32_t id, uintcap_t arg0, uintcap_t arg1, uintcap_t arg2, uintcap_t arg3, uintcap_t arg4, uintcap_t arg5, void *__capability arg6) { TestCall(id, arg0, arg1, arg2, arg3, arg4, arg5, arg6); }
Compile with g++ -march=morello -save-temps -Wall -Wextra -O3 -std=gnu++14 -c test.cpp (Note: different optimisation levels give same failure behaviour).
Resulting generated assembler (tidied - comment added is mine):
stp x29, x30, [sp, -128]! mov x29, sp str c7, [sp, 16] stp c6, c5, [sp, 32] str c2, [sp, 96] str c1, [sp, 112] stp c4, c3, [sp, 64] bl _Z9AsUintcapj ldr c14, [sp, 112] ldp c2, c6, [sp, 16] ldp c8, c4, [sp, 48] ldp c10, c12, [sp, 80] // Args passed as c0, c14, c4, c6, c8, c10, c12 // c2 corrupted; being used for branch address blr c2 ldp x29, x30, [sp], 128 ret
Compare result if not using a template function (modify example code by removing template statement and add using Fn=void *__capability;):
stp x29, x30, [sp, -128]! mov x29, sp str c7, [sp, 16] stp c6, c5, [sp, 32] stp c4, c3, [sp, 64] stp c2, c1, [sp, 96] bl _Z9AsUintcapj ldr c8, [sp, 16] ldp c6, c5, [sp, 32] ldp c4, c3, [sp, 64] ldp c2, c1, [sp, 96] // c0..c6 set correctly as defined arguments. // c8 is used for address; no corruption of registers we are using blr c8 ldp x29, x30, [sp], 128 ret
ThanksPete
Nevermind, on further investigation I can reproduce the issue in the purecap case. Thanks for reporting this.
Hi Alex, I was literally just about to post an update when saw your reply!Yes on purecap it does occur, although for me with no optimisation level i.e -O0 flag. Also on purecap, uintcap_t is not defined therefore I am using uintptr_t on purecap, i.e I have in the code using uintcap_t = uintpr_t; .
Thank you for the link to linaro bugs, will report there in future.
By the way, considering C++ is not supported in gcc on hybrid I have to say it works incredibly well! - for example, it successfully built Arm's morello compartments example (albeit with workarounds for a couple of known issues).