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

```asm
<split_string>:
  endbr64
  push   %rbp
  mov    %rsp,%rbp
  push   %rbx
  sub    $0x58,%rsp
  mov    %rdi,-0x48(%rbp)
  mov    %rsi,-0x50(%rbp)
  mov    %rdx,-0x58(%rbp)
  mov    %ecx,-0x5c(%rbp)
  mov    %r8d,-0x60(%rbp)
  movl   $0x0,-0x38(%rbp)
  movl   $0x0,-0x34(%rbp)
  movl   $0x0,-0x30(%rbp)
  movq   $0x0,-0x20(%rbp)
  mov    -0x58(%rbp),%rax
  movl   $0x0,(%rax)
  mov    -0x48(%rbp),%rax
  mov    %rax,%rdi
  call   <strlen@plt>
  mov    %eax,-0x30(%rbp)
  mov    -0x48(%rbp),%rax
  sub    $0x1,%rax
  mov    %rax,-0x28(%rbp)
  jmp    L8
L38:
  addl   $0x1,-0x34(%rbp)
L8:
  mov    -0x28(%rbp),%rax
  lea    0x1(%rax),%rdx
  mov    -0x50(%rbp),%rax
  mov    %rax,%rsi
  mov    %rdx,%rdi
  call   <strstr@plt>
  mov    %rax,-0x28(%rbp)
  cmpq   $0x0,-0x28(%rbp)
  jne    L38
  cmpl   $0x0,-0x34(%rbp)
  jne    L108
  cmpl   $0x0,-0x30(%rbp)
  jne    L108
  mov    $0x0,%eax
  jmp    L4
L108:
  addl   $0x1,-0x34(%rbp)
  mov    -0x34(%rbp),%eax
  cmp    -0x5c(%rbp),%eax
  jle    L128
  mov    -0x5c(%rbp),%eax
  mov    %eax,-0x34(%rbp)
L128:
  mov    -0x34(%rbp),%eax
  cltq
  shl    $0x3,%eax
  mov    %eax,%edi
  call   <xmalloc@plt>
  mov    %rax,-0x20(%rbp)
  mov    -0x48(%rbp),%rax
  mov    %rax,-0x28(%rbp)
  movl   $0x0,-0x38(%rbp)
  jmp    L66
L107:
  mov    -0x50(%rbp),%rdx
  mov    -0x28(%rbp),%rax
  mov    %rdx,%rsi
  mov    %rax,%rdi
  call   <strstr@plt>
  mov    %rax,-0x18(%rbp)
  cmpq   $0x0,-0x18(%rbp)
  je     L86
  mov    -0x18(%rbp),%rax
  movb   $0x0,(%rax)
L86:
  mov    -0x28(%rbp),%rax
  mov    %rax,%rdi
  call   <strlen@plt>
  mov    %eax,-0x2c(%rbp)
  mov    -0x2c(%rbp),%eax
  cmp    -0x60(%rbp),%eax
  jg     L136
  cmpl   $0x0,-0x2c(%rbp)
  jle    L136
  mov    -0x38(%rbp),%eax
  cltq
  lea    0x0(,%rax,8),%rdx
  mov    -0x20(%rbp),%rax
  lea    (%rdx,%rax,1),%rbx
  mov    -0x28(%rbp),%rax
  mov    %rax,%rdi
  call   <xstrdup@plt>
  mov    %rax,(%rbx)
  jmp    L25
L136:
  subl   $0x1,-0x38(%rbp)
  subl   $0x1,-0x34(%rbp)
  mov    -0x18(%rbp),%rax
  add    $0x1,%rax
  mov    %rax,-0x28(%rbp)
L25:
  cmpq   $0x0,-0x18(%rbp)
  jne    L23
  addl   $0x1,-0x38(%rbp)
  jmp    L36
L23:
  mov    -0x18(%rbp),%rax
  add    $0x1,%rax
  mov    %rax,-0x28(%rbp)
  addl   $0x1,-0x38(%rbp)
L66:
  mov    -0x38(%rbp),%eax
  cmp    -0x34(%rbp),%eax
  jl     L107
L36:
  mov    -0x38(%rbp),%eax
  cmp    -0x34(%rbp),%eax
  je     L115
  mov    -0x38(%rbp),%eax
  cltq
  shl    $0x3,%eax
  mov    %eax,%edx
  mov    -0x20(%rbp),%rax
  mov    %edx,%esi
  mov    %rax,%rdi
  call   <xrealloc@plt>
  mov    %rax,-0x20(%rbp)
L115:
  mov    -0x58(%rbp),%rax
  mov    -0x34(%rbp),%edx
  mov    %edx,(%rax)
  mov    -0x20(%rbp),%rax
L4:
  mov    -0x8(%rbp),%rbx
  leave
  ret
```

assistant: ```c
char **split_string(char *str, const char *div_str, int *substrings, int max_substrings, int max_substring_sz) {
  int i = 0, strings = 0, str_len = 0, buf_len;
  char *buf, **splitted = 0, *p;
  *substrings = 0;
  str_len = strlen(str);
  buf = str - 1;
  while ((buf = strstr((const char *)buf + 1, div_str)))
    strings++;
  if (!strings && !str_len)
    return 0;
  strings++;
  if (strings > max_substrings)
    strings = max_substrings;
  splitted = (char **)xmalloc(sizeof(char *) * strings);
  buf = str;
  for (i = 0; i < strings; i++) {
    p = strstr((const char *)buf, div_str);
    if (p)
      *p = 0;
    buf_len = strlen(buf);
    if (buf_len <= max_substring_sz && buf_len > 0)
      splitted[i] = xstrdup(buf);
    else {
      i--;
      strings--;
      buf = p + 1;
    }
    if (!p) {
      i++;
      break;
    }
    buf = p + 1;
  }
  if (i != strings)
    splitted = (char **)xrealloc(splitted, sizeof(char *) * i);
  *substrings = strings;
  return splitted;
}
```