user: Please show me the C implementation that matches the assembly code listed below:

```asm
<bn_mul_words>:
  endbr64
  push   %r13
  mov    %ecx,%r13d
  push   %r12
  mov    %edx,%r12d
  push   %rbp
  mov    %rsi,%rbp
  push   %rbx
  mov    %rdi,%rbx
  mov    %edx,%edi
  not    %edi
  shr    $0x1f,%edi
  sub    $0x8,%rsp
  call   <assert@plt>
  xor    %eax,%eax
  test   %r12d,%r12d
  jle    L21
  mov    %r13d,%ecx
  movzwl %r13w,%esi
  xor    %r9d,%r9d
  shr    $0x10,%ecx
  jmp    L41
  nopl   0x0(%rax,%rax,1)
L27:
  mov    0x4(%rbp),%r8d
  mov    %esi,%edi
  mov    %ecx,%r9d
  movzwl %r8w,%edx
  shr    $0x10,%r8d
  imul   %edx,%edi
  imul   %r8d,%r9d
  imul   %ecx,%edx
  imul   %esi,%r8d
  add    %r8d,%edx
  jb     L105
L86:
  mov    %edx,%r8d
  shl    $0x10,%edx
  shr    $0x10,%r8d
  add    %edx,%edi
  adc    %r9d,%r8d
  add    %eax,%edi
  mov    %edi,0x4(%rbx)
  adc    $0x0,%r8d
  cmp    $0x2,%r12d
  je     L91
  mov    0x8(%rbp),%r9d
  mov    %esi,%edi
  mov    %ecx,%eax
  movzwl %r9w,%edx
  shr    $0x10,%r9d
  imul   %edx,%edi
  imul   %r9d,%eax
  imul   %ecx,%edx
  imul   %esi,%r9d
  add    %r9d,%edx
  jb     L131
L40:
  mov    %edx,%r9d
  shl    $0x10,%edx
  shr    $0x10,%r9d
  add    %edx,%edi
  adc    %r9d,%eax
  add    %r8d,%edi
  mov    %edi,0x8(%rbx)
  adc    $0x0,%eax
  cmp    $0x3,%r12d
  je     L21
  mov    0xc(%rbp),%r8d
  mov    %esi,%edi
  mov    %ecx,%r9d
  movzwl %r8w,%edx
  shr    $0x10,%r8d
  imul   %edx,%edi
  imul   %r8d,%r9d
  imul   %ecx,%edx
  imul   %esi,%r8d
  add    %r8d,%edx
  jb     L1
L33:
  mov    %edx,%r8d
  shl    $0x10,%edx
  shr    $0x10,%r8d
  add    %edx,%edi
  adc    %r8d,%r9d
  add    %eax,%edi
  mov    %edi,0xc(%rbx)
  adc    $0x0,%r9d
  sub    $0x4,%r12d
  je     L32
  add    $0x10,%rbp
  add    $0x10,%rbx
L41:
  mov    0x0(%rbp),%r8d
  mov    %esi,%edi
  mov    %ecx,%eax
  movzwl %r8w,%edx
  shr    $0x10,%r8d
  imul   %edx,%edi
  imul   %r8d,%eax
  imul   %ecx,%edx
  imul   %esi,%r8d
  add    %r8d,%edx
  jb     L78
L14:
  mov    %edx,%r8d
  shl    $0x10,%edx
  shr    $0x10,%r8d
  add    %edx,%edi
  adc    %r8d,%eax
  add    %r9d,%edi
  mov    %edi,(%rbx)
  adc    $0x0,%eax
  cmp    $0x1,%r12d
  jne    L27
L21:
  add    $0x8,%rsp
  pop    %rbx
  pop    %rbp
  pop    %r12
  pop    %r13
  ret
  nopl   0x0(%rax,%rax,1)
L91:
  add    $0x8,%rsp
  mov    %r8d,%eax
  pop    %rbx
  pop    %rbp
  pop    %r12
  pop    %r13
  ret
  xchg   %ax,%ax
L32:
  add    $0x8,%rsp
  mov    %r9d,%eax
  pop    %rbx
  pop    %rbp
  pop    %r12
  pop    %r13
  ret
L131:
  add    $0x10000,%eax
  jmp    L40
L78:
  add    $0x10000,%eax
  jmp    L14
L1:
  add    $0x10000,%r9d
  jmp    L33
L105:
  add    $0x10000,%r9d
  jmp    L86
```

assistant: ```c
unsigned int bn_mul_words(unsigned int *rp, const unsigned int *ap, int num, unsigned int w) {
  unsigned int carry = 0;
  unsigned int bl, bh;
  assert(num >= 0);
  if (num <= 0)
    return (unsigned int)0;
  bl = ((w) & (0xffff));
  bh = (((w) >> 16) & (0xffff));
  for (;;) {
    {
      unsigned int l, h;
      h = (ap[0]);
      l = ((h) & (0xffff));
      h = (((h) >> 16) & (0xffff));
      {
        unsigned int m, m1, lt, ht;
        lt = l;
        ht = h;
        m = ((bh)) * (lt);
        lt = ((bl)) * (lt);
        m1 = ((bl)) * (ht);
        ht = ((bh)) * (ht);
        m = (m + m1) & (0xffffffffL);
        if (m < m1)
          ht += ((unsigned int)((1L) & (0xffff)) << 16);
        ht += (((m) >> 16) & (0xffff));
        m1 = ((unsigned int)((m) & (0xffff)) << 16);
        lt = (lt + m1) & (0xffffffffL);
        if (lt < m1)
          ht++;
        (l) = lt;
        (h) = ht;
      };
      l += (carry);
      if ((l & (0xffffffffL)) < (carry))
        h++;
      (carry) = h & (0xffffffffL);
      (rp[0]) = l & (0xffffffffL);
    };
    if (--num == 0)
      break;
    {
      unsigned int l, h;
      h = (ap[1]);
      l = ((h) & (0xffff));
      h = (((h) >> 16) & (0xffff));
      {
        unsigned int m, m1, lt, ht;
        lt = l;
        ht = h;
        m = ((bh)) * (lt);
        lt = ((bl)) * (lt);
        m1 = ((bl)) * (ht);
        ht = ((bh)) * (ht);
        m = (m + m1) & (0xffffffffL);
        if (m < m1)
          ht += ((unsigned int)((1L) & (0xffff)) << 16);
        ht += (((m) >> 16) & (0xffff));
        m1 = ((unsigned int)((m) & (0xffff)) << 16);
        lt = (lt + m1) & (0xffffffffL);
        if (lt < m1)
          ht++;
        (l) = lt;
        (h) = ht;
      };
      l += (carry);
      if ((l & (0xffffffffL)) < (carry))
        h++;
      (carry) = h & (0xffffffffL);
      (rp[1]) = l & (0xffffffffL);
    };
    if (--num == 0)
      break;
    {
      unsigned int l, h;
      h = (ap[2]);
      l = ((h) & (0xffff));
      h = (((h) >> 16) & (0xffff));
      {
        unsigned int m, m1, lt, ht;
        lt = l;
        ht = h;
        m = ((bh)) * (lt);
        lt = ((bl)) * (lt);
        m1 = ((bl)) * (ht);
        ht = ((bh)) * (ht);
        m = (m + m1) & (0xffffffffL);
        if (m < m1)
          ht += ((unsigned int)((1L) & (0xffff)) << 16);
        ht += (((m) >> 16) & (0xffff));
        m1 = ((unsigned int)((m) & (0xffff)) << 16);
        lt = (lt + m1) & (0xffffffffL);
        if (lt < m1)
          ht++;
        (l) = lt;
        (h) = ht;
      };
      l += (carry);
      if ((l & (0xffffffffL)) < (carry))
        h++;
      (carry) = h & (0xffffffffL);
      (rp[2]) = l & (0xffffffffL);
    };
    if (--num == 0)
      break;
    {
      unsigned int l, h;
      h = (ap[3]);
      l = ((h) & (0xffff));
      h = (((h) >> 16) & (0xffff));
      {
        unsigned int m, m1, lt, ht;
        lt = l;
        ht = h;
        m = ((bh)) * (lt);
        lt = ((bl)) * (lt);
        m1 = ((bl)) * (ht);
        ht = ((bh)) * (ht);
        m = (m + m1) & (0xffffffffL);
        if (m < m1)
          ht += ((unsigned int)((1L) & (0xffff)) << 16);
        ht += (((m) >> 16) & (0xffff));
        m1 = ((unsigned int)((m) & (0xffff)) << 16);
        lt = (lt + m1) & (0xffffffffL);
        if (lt < m1)
          ht++;
        (l) = lt;
        (h) = ht;
      };
      l += (carry);
      if ((l & (0xffffffffL)) < (carry))
        h++;
      (carry) = h & (0xffffffffL);
      (rp[3]) = l & (0xffffffffL);
    };
    if (--num == 0)
      break;
    ap += 4;
    rp += 4;
  }
  return carry;
}
```