user: 请将以下的汇编代码转换成C语言代码：

```asm
<md5_hash>:
  endbr64
  push   %rbp
  mov    %rsp,%rbp
  push   %rbx
  sub    $0x88,%rsp
  mov    %rdi,-0x78(%rbp)
  mov    %esi,-0x7c(%rbp)
  mov    %rdx,-0x88(%rbp)
  mov    %fs:0x28,%rax
  mov    %rax,-0x18(%rbp)
  xor    %eax,%eax
  mov    $0x67452301,%edi
  call   <UINT32_C@plt>
  mov    -0x88(%rbp),%rdx
  mov    %eax,(%rdx)
  mov    -0x88(%rbp),%rax
  lea    0x4(%rax),%rbx
  mov    $0xefcdab89,%edi
  call   <UINT32_C@plt>
  mov    %eax,(%rbx)
  mov    -0x88(%rbp),%rax
  lea    0x8(%rax),%rbx
  mov    $0x98badcfe,%edi
  call   <UINT32_C@plt>
  mov    %eax,(%rbx)
  mov    -0x88(%rbp),%rax
  lea    0xc(%rax),%rbx
  mov    $0x10325476,%edi
  call   <UINT32_C@plt>
  mov    %eax,(%rbx)
  movl   $0x0,-0x70(%rbp)
  jmp    L14
L3:
  mov    -0x70(%rbp),%eax
  cltq
  lea    0x0(,%rax,4),%rdx
  mov    -0x78(%rbp),%rax
  add    %rax,%rdx
  mov    -0x88(%rbp),%rax
  mov    %rdx,%rsi
  mov    %rax,%rdi
  call   <md5_compress@plt>
  addl   $0x40,-0x70(%rbp)
L14:
  mov    -0x70(%rbp),%eax
  add    $0x3f,%eax
  cmp    %eax,-0x7c(%rbp)
  jg     L3
  lea    -0x60(%rbp),%rax
  mov    %rax,-0x68(%rbp)
  mov    -0x7c(%rbp),%eax
  sub    -0x70(%rbp),%eax
  mov    %eax,-0x6c(%rbp)
  mov    -0x70(%rbp),%eax
  cltq
  lea    0x0(,%rax,4),%rdx
  mov    -0x78(%rbp),%rax
  lea    (%rdx,%rax,1),%rcx
  mov    -0x6c(%rbp),%edx
  mov    -0x68(%rbp),%rax
  mov    %rcx,%rsi
  mov    %rax,%rdi
  call   <memcpy@plt>
  mov    -0x6c(%rbp),%eax
  cltq
  lea    0x0(,%rax,4),%rdx
  mov    -0x68(%rbp),%rax
  add    %rdx,%rax
  movl   $0x80,(%rax)
  addl   $0x1,-0x6c(%rbp)
  mov    $0x40,%eax
  sub    -0x6c(%rbp),%eax
  cmp    $0x7,%eax
  jle    L16
  mov    $0x38,%eax
  sub    -0x6c(%rbp),%eax
  mov    -0x6c(%rbp),%edx
  movslq %edx,%rdx
  lea    0x0(,%rdx,4),%rcx
  mov    -0x68(%rbp),%rdx
  add    %rdx,%rcx
  mov    %eax,%edx
  mov    $0x0,%esi
  mov    %rcx,%rdi
  call   <memset@plt>
  jmp    L26
L16:
  mov    $0x40,%eax
  sub    -0x6c(%rbp),%eax
  mov    -0x6c(%rbp),%edx
  movslq %edx,%rdx
  lea    0x0(,%rdx,4),%rcx
  mov    -0x68(%rbp),%rdx
  add    %rdx,%rcx
  mov    %eax,%edx
  mov    $0x0,%esi
  mov    %rcx,%rdi
  call   <memset@plt>
  lea    -0x60(%rbp),%rdx
  mov    -0x88(%rbp),%rax
  mov    %rdx,%rsi
  mov    %rax,%rdi
  call   <md5_compress@plt>
  lea    -0x60(%rbp),%rax
  mov    $0x38,%edx
  mov    $0x0,%esi
  mov    %rax,%rdi
  call   <memset@plt>
L26:
  mov    -0x7c(%rbp),%eax
  shl    $0x3,%eax
  mov    %eax,-0x28(%rbp)
  mov    -0x7c(%rbp),%eax
  sar    $0x1d,%eax
  mov    %eax,-0x24(%rbp)
  lea    -0x60(%rbp),%rdx
  mov    -0x88(%rbp),%rax
  mov    %rdx,%rsi
  mov    %rax,%rdi
  call   <md5_compress@plt>
  nop
  mov    -0x18(%rbp),%rax
  sub    %fs:0x28,%rax
  je     L12
  call   <__stack_chk_fail@plt>
L12:
  mov    -0x8(%rbp),%rbx
  leave
  ret
```

assistant: ```c
void md5_hash(uint8_t *message, uint32_t len, uint32_t *hash) {
  hash[0] = UINT32_C(0x67452301);
  hash[1] = UINT32_C(0xEFCDAB89);
  hash[2] = UINT32_C(0x98BADCFE);
  hash[3] = UINT32_C(0x10325476);
  int i;
  for (i = 0; i + 64 <= len; i += 64)
    md5_compress(hash, (uint32_t *)(message + i));
  uint32_t block[16];
  uint8_t *byteBlock = (uint8_t *)block;
  int rem = len - i;
  memcpy(byteBlock, message + i, rem);
  byteBlock[rem] = 0x80;
  rem++;
  if (64 - rem >= 8)
    memset(byteBlock + rem, 0, 56 - rem);
  else {
    memset(byteBlock + rem, 0, 64 - rem);
    md5_compress(hash, block);
    memset(block, 0, 56);
  }
  block[14] = len << 3;
  block[15] = len >> 29;
  md5_compress(hash, block);
}
```