Uploaded image for project: 'MariaDB Server'
  1. MariaDB Server
  2. MDEV-34815

SIGILL error when executing mariadbd compiled for RISC-V with Clang

Details

    • Bug
    • Status: Closed (View Workflow)
    • Major
    • Resolution: Fixed
    • None
    • 10.11.11, 11.4.5, 11.7.2
    • Server
    • None
    • Clang version: 17
      Target architecture: RISC-V

    Description

      Problem Description

      When executing the mariadbd binary compiled for the RISC-V architecture using Clang 17, a SIGILL error occurs. The compilation process itself completes without errors. I believe this runtime error may be related to the use of __builtin_readcyclecounter in the my_timer_cycles function (in include/my_rdtsc.h), which seems to generate an rdcycle instruction that is illegal to execute in user mode on RISC-V.

      Steps to Reproduce

      Compile MariaDB/server for RISC-V architecture using Clang 17
      execute ./sql/mariadb
      The compilation process triggers a SIGILL error

      Analysis

      In include/my_rdtsc.h, the my_timer_cycles function uses __builtin_readcyclecounter
      A simple test program was written to verify the behavior of __builtin_readcyclecounter
      Using objdump to analyze the compiled binary confirms the generation of the rdcycle instruction
      In RISC-V architecture, rdcycle is a privileged instruction, execution in user mode triggers a SIGILL error

      Relevant Code

      // Test code
      int main() {
          unsigned long cycles;
          cycles = __builtin_readcyclecounter();
          printf("Cycle count: %lu\n", cycles);
          return 0;
      }
       
      // objdump
      0000000000000668 <main>:
      ...
       672:	fca43c23          	sd	a0,-40(s0)
       676:	fea42623          	sw	a0,-20(s0)
       67a:	c0002573          	rdcycle	a0
       67e:	fea43023          	sd	a0,-32(s0)
       ...
       69c:	8082                	ret
      

      If this issue is confirmed, one possible solution might be to modify the condition in include/my_rdtsc.h to explicitly use the RISC-V specific implementation:

      # if __has_builtin(__builtin_readcyclecounter) && !defined(__aarch64__) && !defined(__riscv)
      

      static inline ulonglong my_timer_cycles(void)
      {
      # if __has_builtin(__builtin_readcyclecounter) && !defined (__aarch64__) 
        #define MY_TIMER_ROUTINE_CYCLES MY_TIMER_ROUTINE_AARCH64
        return __builtin_readcyclecounter();
      ...
      #elif defined(__riscv)
        #define MY_TIMER_ROUTINE_CYCLES MY_TIMER_ROUTINE_RISCV
        /* Use RDTIME (and RDTIMEH on riscv32) */
        {
      # if __riscv_xlen == 32
          ulong result_lo, result_hi0, result_hi1;
          /* Implemented in assembly because Clang insisted on branching. */
          __asm __volatile__(
              "rdtimeh %0\n"
              "rdtime %1\n"
              "rdtimeh %2\n"
              "sub %0, %0, %2\n"
              "seqz %0, %0\n"
              "sub %0, zero, %0\n"
              "and %1, %1, %0\n"
              : "=r"(result_hi0), "=r"(result_lo), "=r"(result_hi1));
          return (static_cast<ulonglong>(result_hi1) << 32) | result_lo;
      # else
          ulonglong result;
          __asm __volatile__("rdtime %0" : "=r"(result));
          return result;
        }
      # endif
      #elif defined(HAVE_SYS_TIMES_H) && defined(HAVE_GETHRTIME)
        #define MY_TIMER_ROUTINE_CYCLES MY_TIMER_ROUTINE_GETHRTIME
        /* gethrtime may appear as either cycle or nanosecond counter */
        return (ulonglong) gethrtime();
      #else
        #define MY_TIMER_ROUTINE_CYCLES 0
        return 0;
      #endif
      }
      

      Attachments

        Issue Links

          Activity

            Thanks for pointing out MDEV-33435. It seems that it addresses the issue in my_rdtsc.h, so this ticket can be closed now.
            Please, comment, if I'm wrong, and I'll reopen.

            serg Sergei Golubchik added a comment - Thanks for pointing out MDEV-33435 . It seems that it addresses the issue in my_rdtsc.h, so this ticket can be closed now. Please, comment, if I'm wrong, and I'll reopen.
            zzbs BINSZ added a comment -

            @serg Thank you for reply. While MDEV-33435 does address part of the issue in my_rdtsc.h, I believe the problem still persists when compiling for RISC-V using Clang. Here's why:

            • The current logic in my_rdtsc.h is:

            static inline ulonglong my_timer_cycles(void)
            {
            # if __has_builtin(__builtin_readcyclecounter) && !defined (__aarch64__)
              #define MY_TIMER_ROUTINE_CYCLES MY_TIMER_ROUTINE_AARCH64
              return __builtin_readcyclecounter();
            // .....
            #elif defined(__riscv)
              #define MY_TIMER_ROUTINE_CYCLES MY_TIMER_ROUTINE_RISCV
              /* Use RDTIME (and RDTIMEH on riscv32) */
              {
            # if __riscv_xlen == 32
                ulong result_lo, result_hi0, result_hi1;
                /* Implemented in assembly because Clang insisted on branching. */
                __asm __volatile__(
                    "rdtimeh %0\n"
                    "rdtime %1\n"
                    "rdtimeh %2\n"
                    "sub %0, %0, %2\n"
                    "seqz %0, %0\n"
                    "sub %0, zero, %0\n"
                    "and %1, %1, %0\n"
                    : "=r"(result_hi0), "=r"(result_lo), "=r"(result_hi1));
                return (static_cast<ulonglong>(result_hi1) << 32) | result_lo;
            # else
                ulonglong result;
                __asm __volatile__("rdtime %0" : "=r"(result));
                return result;
              }
            # endif
            

            • This condition first checks if __builtin_readcyclecounter is available, which it is in Clang.
            • When compiling for RISC-V with Clang, this condition is true, so it uses `__builtin_readcyclecounter()`.
            • However, in Clang 17, __builtin_readcyclecounter() generates an rdcycle instruction for RISC-V, which is illegal in user mode on Linux 6.6+. Example

            So, while MDEV-33435 addresses the issue for some cases, it doesn't cover the specific scenario of using Clang for RISC-V targets.

            Given this, I believe this issue should remain open.

            zzbs BINSZ added a comment - @serg Thank you for reply. While MDEV-33435 does address part of the issue in my_rdtsc.h, I believe the problem still persists when compiling for RISC-V using Clang. Here's why: The current logic in my_rdtsc.h is: static inline ulonglong my_timer_cycles( void ) { # if __has_builtin(__builtin_readcyclecounter) && !defined (__aarch64__) #define MY_TIMER_ROUTINE_CYCLES MY_TIMER_ROUTINE_AARCH64 return __builtin_readcyclecounter(); // ..... #elif defined(__riscv) #define MY_TIMER_ROUTINE_CYCLES MY_TIMER_ROUTINE_RISCV /* Use RDTIME (and RDTIMEH on riscv32) */ { # if __riscv_xlen == 32 ulong result_lo, result_hi0, result_hi1; /* Implemented in assembly because Clang insisted on branching. */ __asm __volatile__( "rdtimeh %0\n" "rdtime %1\n" "rdtimeh %2\n" "sub %0, %0, %2\n" "seqz %0, %0\n" "sub %0, zero, %0\n" "and %1, %1, %0\n" : "=r" (result_hi0), "=r" (result_lo), "=r" (result_hi1)); return ( static_cast <ulonglong>(result_hi1) << 32) | result_lo; # else ulonglong result; __asm __volatile__( "rdtime %0" : "=r" (result)); return result; } # endif This condition first checks if __builtin_readcyclecounter is available, which it is in Clang. When compiling for RISC-V with Clang, this condition is true, so it uses `__builtin_readcyclecounter()`. However, in Clang 17, __builtin_readcyclecounter() generates an rdcycle instruction for RISC-V, which is illegal in user mode on Linux 6.6+. Example So, while MDEV-33435 addresses the issue for some cases, it doesn't cover the specific scenario of using Clang for RISC-V targets. Given this, I believe this issue should remain open.

            I guess, something like that

               A cycle timer.
             
            -  On clang we use __builtin_readcyclecounter(), except for AARCH64.
            +  On clang we use __builtin_readcyclecounter(), except for AARCH64 and RISC-V
               On other compilers:
            

            is needed, then

            serg Sergei Golubchik added a comment - I guess, something like that A cycle timer. - On clang we use __builtin_readcyclecounter(), except for AARCH64. + On clang we use __builtin_readcyclecounter(), except for AARCH64 and RISC-V On other compilers: is needed, then
            danblack Daniel Black added a comment -

            Very basic, thanks zzbs, implemented as described

            Acceptable https://github.com/MariaDB/server/pull/3661

            danblack Daniel Black added a comment - Very basic, thanks zzbs , implemented as described Acceptable https://github.com/MariaDB/server/pull/3661
            danblack Daniel Black added a comment -

            Thanks knielsen for the review

            danblack Daniel Black added a comment - Thanks knielsen for the review

            People

              danblack Daniel Black
              zzbs BINSZ
              Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved:

                Git Integration

                  Error rendering 'com.xiplink.jira.git.jira_git_plugin:git-issue-webpanel'. Please contact your Jira administrators.