We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
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