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

```asm
<bn_add_words>:
  endbr64
  push   %rbp
  mov    %rsp,%rbp
  sub    $0x40,%rsp
  mov    %rdi,-0x28(%rbp)
  mov    %rsi,-0x30(%rbp)
  mov    %rdx,-0x38(%rbp)
  mov    %ecx,-0x3c(%rbp)
  mov    -0x3c(%rbp),%eax
  not    %eax
  shr    $0x1f,%eax
  movzbl %al,%eax
  mov    %eax,%edi
  call   <assert@plt>
  cmpl   $0x0,-0x3c(%rbp)
  jg     L38
  mov    $0x0,%eax
  jmp    L77
L38:
  movq   $0x0,-0x18(%rbp)
L74:
  mov    -0x30(%rbp),%rax
  mov    (%rax),%rax
  mov    %rax,-0x10(%rbp)
  mov    -0x18(%rbp),%rax
  add    %rax,-0x10(%rbp)
  mov    -0x10(%rbp),%rax
  cmp    -0x18(%rbp),%rax
  setb   %al
  movzbl %al,%eax
  mov    %rax,-0x18(%rbp)
  mov    -0x38(%rbp),%rax
  mov    (%rax),%rdx
  mov    -0x10(%rbp),%rax
  add    %rdx,%rax
  mov    %rax,-0x8(%rbp)
  mov    -0x8(%rbp),%rax
  cmp    -0x10(%rbp),%rax
  setb   %al
  movzbl %al,%eax
  add    %rax,-0x18(%rbp)
  mov    -0x28(%rbp),%rax
  mov    -0x8(%rbp),%rdx
  mov    %rdx,(%rax)
  subl   $0x1,-0x3c(%rbp)
  cmpl   $0x0,-0x3c(%rbp)
  jle    L72
  mov    -0x30(%rbp),%rax
  mov    0x8(%rax),%rax
  mov    %rax,-0x10(%rbp)
  mov    -0x18(%rbp),%rax
  add    %rax,-0x10(%rbp)
  mov    -0x10(%rbp),%rax
  cmp    -0x18(%rbp),%rax
  setb   %al
  movzbl %al,%eax
  mov    %rax,-0x18(%rbp)
  mov    -0x38(%rbp),%rax
  add    $0x8,%rax
  mov    (%rax),%rdx
  mov    -0x10(%rbp),%rax
  add    %rdx,%rax
  mov    %rax,-0x8(%rbp)
  mov    -0x8(%rbp),%rax
  cmp    -0x10(%rbp),%rax
  setb   %al
  movzbl %al,%eax
  add    %rax,-0x18(%rbp)
  mov    -0x28(%rbp),%rax
  lea    0x8(%rax),%rdx
  mov    -0x8(%rbp),%rax
  mov    %rax,(%rdx)
  subl   $0x1,-0x3c(%rbp)
  cmpl   $0x0,-0x3c(%rbp)
  jle    L5
  mov    -0x30(%rbp),%rax
  mov    0x10(%rax),%rax
  mov    %rax,-0x10(%rbp)
  mov    -0x18(%rbp),%rax
  add    %rax,-0x10(%rbp)
  mov    -0x10(%rbp),%rax
  cmp    -0x18(%rbp),%rax
  setb   %al
  movzbl %al,%eax
  mov    %rax,-0x18(%rbp)
  mov    -0x38(%rbp),%rax
  add    $0x10,%rax
  mov    (%rax),%rdx
  mov    -0x10(%rbp),%rax
  add    %rdx,%rax
  mov    %rax,-0x8(%rbp)
  mov    -0x8(%rbp),%rax
  cmp    -0x10(%rbp),%rax
  setb   %al
  movzbl %al,%eax
  add    %rax,-0x18(%rbp)
  mov    -0x28(%rbp),%rax
  lea    0x10(%rax),%rdx
  mov    -0x8(%rbp),%rax
  mov    %rax,(%rdx)
  subl   $0x1,-0x3c(%rbp)
  cmpl   $0x0,-0x3c(%rbp)
  jle    L41
  mov    -0x30(%rbp),%rax
  mov    0x18(%rax),%rax
  mov    %rax,-0x10(%rbp)
  mov    -0x18(%rbp),%rax
  add    %rax,-0x10(%rbp)
  mov    -0x10(%rbp),%rax
  cmp    -0x18(%rbp),%rax
  setb   %al
  movzbl %al,%eax
  mov    %rax,-0x18(%rbp)
  mov    -0x38(%rbp),%rax
  add    $0x18,%rax
  mov    (%rax),%rdx
  mov    -0x10(%rbp),%rax
  add    %rdx,%rax
  mov    %rax,-0x8(%rbp)
  mov    -0x8(%rbp),%rax
  cmp    -0x10(%rbp),%rax
  setb   %al
  movzbl %al,%eax
  add    %rax,-0x18(%rbp)
  mov    -0x28(%rbp),%rax
  lea    0x18(%rax),%rdx
  mov    -0x8(%rbp),%rax
  mov    %rax,(%rdx)
  subl   $0x1,-0x3c(%rbp)
  cmpl   $0x0,-0x3c(%rbp)
  jle    L55
  addq   $0x20,-0x30(%rbp)
  addq   $0x20,-0x38(%rbp)
  addq   $0x20,-0x28(%rbp)
  jmp    L74
L72:
  nop
  jmp    L95
L5:
  nop
  jmp    L95
L41:
  nop
  jmp    L95
L55:
  nop
L95:
  mov    -0x18(%rbp),%rax
L77:
  leave
  ret
```

assistant: ```c
unsigned long long bn_add_words(unsigned long long *r, unsigned long long *a, unsigned long long *b, int n) {
  unsigned long long c, l, t;
  assert(n >= 0);
  if (n <= 0)
    return ((unsigned long long)0);
  c = 0;
  for (;;) {
    t = a[0];
    t = (t + c) & (0xffffffffffffffffLL);
    c = (t < c);
    l = (t + b[0]) & (0xffffffffffffffffLL);
    c += (l < t);
    r[0] = l;
    if (--n <= 0)
      break;
    t = a[1];
    t = (t + c) & (0xffffffffffffffffLL);
    c = (t < c);
    l = (t + b[1]) & (0xffffffffffffffffLL);
    c += (l < t);
    r[1] = l;
    if (--n <= 0)
      break;
    t = a[2];
    t = (t + c) & (0xffffffffffffffffLL);
    c = (t < c);
    l = (t + b[2]) & (0xffffffffffffffffLL);
    c += (l < t);
    r[2] = l;
    if (--n <= 0)
      break;
    t = a[3];
    t = (t + c) & (0xffffffffffffffffLL);
    c = (t < c);
    l = (t + b[3]) & (0xffffffffffffffffLL);
    c += (l < t);
    r[3] = l;
    if (--n <= 0)
      break;
    a += 4;
    b += 4;
    r += 4;
  }
  return ((unsigned long long)c);
}
```