user: 请显示与下面列出的汇编代码相匹配的C语言实现：

```asm
<read_image>:
  endbr64
  push   %r15
  push   %r14
  push   %r13
  push   %r12
  push   %rbp
  push   %rbx
  sub    $0x98,%rsp
  mov    %rdi,%r14
  mov    %rdx,0x8(%rsp)
  mov    %rcx,0x10(%rsp)
  mov    %r8,0x18(%rsp)
  mov    %fs:0x28,%rax
  mov    %rax,0x88(%rsp)
  xor    %eax,%eax
  lea    D27(%rip),%rsi
  lea    D37(%rip),%rdi
  call   <fopen@plt>
  mov    %rax,%r12
  test   %rax,%rax
  je     L52
L65:
  lea    0x30(%rsp),%rbx
  mov    %rbx,%rdx
  lea    D12(%rip),%rsi
  mov    %r12,%rdi
  mov    $0x0,%eax
  call   <fscanf@plt>
  lea    D82(%rip),%rsi
  mov    %rbx,%rdi
  call   <strcmp@plt>
  test   %rax,%rax
  jne    L23
L30:
  lea    0x30(%rsp),%rbx
  mov    %r12,%rdx
  mov    $0x50,%esi
  mov    %rbx,%rdi
  call   <fgets@plt>
  mov    %r12,%rdx
  mov    $0x50,%esi
  mov    %rbx,%rdi
  call   <fgets@plt>
  lea    0x24(%rsp),%rcx
  lea    0x28(%rsp),%rdx
  lea    D13(%rip),%rsi
  mov    %r12,%rdi
  mov    $0x0,%eax
  call   <fscanf@plt>
  lea    0x2c(%rsp),%rdx
  lea    D85(%rip),%rsi
  mov    %r12,%rdi
  mov    $0x0,%eax
  call   <fscanf@plt>
  mov    0x28(%rsp),%edx
  mov    0x24(%rsp),%esi
  lea    D98(%rip),%rdi
  mov    $0x0,%eax
  call   <printf@plt>
  cmpl   $0x0,0x24(%rsp)
  jle    L14
  mov    $0x0,%r15d
  lea    D85(%rip),%r13
  jmp    L21
L52:
  lea    D2(%rip),%rdi
  call   <puts@plt>
  mov    $0xffffffff,%edi
  call   <exit@plt>
  jmp    L65
L23:
  lea    D29(%rip),%rdi
  call   <puts@plt>
  mov    $0xffffffff,%edi
  call   <exit@plt>
  jmp    L30
L61:
  mov    %rbp,%rdx
  mov    %r13,%rsi
  mov    %r12,%rdi
  mov    $0x0,%eax
  call   <fscanf@plt>
  add    $0x1,%ebx
  add    $0x4,%rbp
  cmp    %ebx,0x28(%rsp)
  jg     L61
L19:
  add    $0x1,%r15d
  add    $0xebc,%r14
  cmp    %r15d,0x24(%rsp)
  jle    L14
L21:
  mov    %r14,%rbp
  mov    $0x0,%ebx
  cmpl   $0x0,0x28(%rsp)
  jg     L61
  jmp    L19
L14:
  mov    %r12,%rdi
  call   <fclose@plt>
  mov    0x24(%rsp),%eax
  mov    0x8(%rsp),%rcx
  mov    %eax,(%rcx)
  mov    0x28(%rsp),%eax
  mov    0x10(%rsp),%rcx
  mov    %eax,(%rcx)
  mov    0x2c(%rsp),%eax
  mov    0x18(%rsp),%rcx
  mov    %eax,(%rcx)
  mov    0x88(%rsp),%rax
  sub    %fs:0x28,%rax
  jne    L96
  add    $0x98,%rsp
  pop    %rbx
  pop    %rbp
  pop    %r12
  pop    %r13
  pop    %r14
  pop    %r15
  ret
L96:
  call   <__stack_chk_fail@plt>
```

tool_calls: name: disassemble_data
arguments: data_tag: D27
type_infered: string
name: disassemble_data
arguments: data_tag: D37
type_infered: string
name: disassemble_data
arguments: data_tag: D12
type_infered: string
name: disassemble_data
arguments: data_tag: D82
type_infered: string
name: disassemble_data
arguments: data_tag: D13
type_infered: string
name: disassemble_data
arguments: data_tag: D85
type_infered: string
name: disassemble_data
arguments: data_tag: D98
type_infered: string
name: disassemble_data
arguments: data_tag: D2
type_infered: string
name: disassemble_data
arguments: data_tag: D29
type_infered: string

tool: D27: r

tool: D37: logo.pgm

tool: D12: %s

tool: D82: P2

tool: D13: %d%d

tool: D85: %d

tool: D98: image reading ... h = %d w = %d


tool: D2: file open error

tool: D29: the image format must be P2

assistant: ```c
void read_image(int image[827][943], char file_name[], int *p_h, int *p_w, int *p_levels) {
  FILE *fin;
  int i, j, h, w, levels;
  char buffer[80];
  fin = fopen("logo.pgm", "r");
  if (fin == NULL) {
    printf("file open error\n");
    exit(-1);
  }
  fscanf(fin, "%s", buffer);
  if (strcmp(buffer, "P2")) {
    printf("the image format must be P2\n");
    exit(-1);
  }
  fgets(buffer, 80, fin);
  fgets(buffer, 80, fin);
  fscanf(fin, "%d%d", &w, &h);
  fscanf(fin, "%d", &levels);
  printf("image reading ... h = %d w = %d\n", h, w);
  for (i = 0; i < h; i++)
    for (j = 0; j < w; j++)
      fscanf(fin, "%d", &image[i][j]);
  fclose(fin);
  *p_h = h;
  *p_w = w;
  *p_levels = levels;
  return;
}
```