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

```asm
<extract_image>:
  endbr64
  push   %r14
  mov    %r8d,%r14d
  push   %r13
  mov    %edx,%r13d
  push   %r12
  mov    %rdi,%r12
  push   %rbp
  mov    %r9,%rbp
  push   %rbx
  mov    %ecx,%ebx
  add    $0xffffffffffffff80,%rsp
  mov    %fs:0x28,%rdx
  mov    %rdx,0x78(%rsp)
  xor    %edx,%edx
  movslq %esi,%rdx
  movq   $0x0,0x10(%rsp)
  movq   $0x0,0x18(%rsp)
  lea    -0x20000000(%rdi,%rdx,4),%rdi
  movq   $0x0,0x20(%rsp)
  test   %ecx,%ecx
  jne    L49
  mov    %rdi,0x20(%rsp)
L57:
  movq   $0x0,0x28(%rsp)
  movslq %r13d,%rax
  lea    -0x20000000(%r12,%rax,4),%rdi
  test   %r14d,%r14d
  jne    L51
  mov    %rdi,0x28(%rsp)
L12:
  pxor   %xmm0,%xmm0
  movaps %xmm0,0x30(%rsp)
  movaps %xmm0,0x40(%rsp)
  movaps %xmm0,0x50(%rsp)
  movaps %xmm0,0x60(%rsp)
  mov    (%rdi),%edx
  mov    %edx,%eax
  mov    %edx,%ecx
  shl    $0x3,%edx
  shl    $0x9,%eax
  shl    $0x6,%ecx
  movzbl %dl,%edx
  and    $0xf800,%ecx
  and    $0xf80000,%eax
  or     %ecx,%eax
  or     %edx,%eax
  mov    0x4(%rdi),%edx
  mov    %eax,0x30(%rsp)
  mov    %edx,%ecx
  mov    %edx,%eax
  shl    $0x3,%edx
  shl    $0x9,%eax
  shl    $0x6,%ecx
  movzbl %dl,%edx
  and    $0xf800,%ecx
  and    $0xf80000,%eax
  or     %ecx,%eax
  or     %edx,%eax
  mov    0x8(%rdi),%edx
  or     $0xff000000,%eax
  mov    %eax,0x34(%rsp)
  mov    %edx,%ecx
  mov    %edx,%eax
  shl    $0x3,%edx
  shl    $0x6,%eax
  shl    $0x9,%ecx
  movzbl %dl,%edx
  and    $0xf80000,%ecx
  and    $0xf800,%eax
  or     %ecx,%eax
  or     %edx,%eax
  mov    0xc(%rdi),%edx
  or     $0xff000000,%eax
  mov    %eax,0x38(%rsp)
  mov    %edx,%ecx
  mov    %edx,%eax
  shl    $0x3,%edx
  shl    $0x6,%eax
  shl    $0x9,%ecx
  movzbl %dl,%edx
  and    $0xf80000,%ecx
  and    $0xf800,%eax
  or     %ecx,%eax
  or     %edx,%eax
  mov    0x10(%rdi),%edx
  or     $0xff000000,%eax
  mov    %eax,0x3c(%rsp)
  mov    %edx,%eax
  mov    %edx,%ecx
  shl    $0x6,%eax
  and    $0xf800,%eax
  shl    $0x9,%ecx
  and    $0xf80000,%ecx
  shl    $0x3,%edx
  or     %ecx,%eax
  movzbl %dl,%edx
  or     %edx,%eax
  mov    0x14(%rdi),%edx
  or     $0xff000000,%eax
  mov    %eax,0x40(%rsp)
  mov    %edx,%ecx
  mov    %edx,%eax
  shl    $0x3,%edx
  shl    $0x6,%eax
  shl    $0x9,%ecx
  movzbl %dl,%edx
  and    $0xf80000,%ecx
  and    $0xf800,%eax
  or     %ecx,%eax
  or     %edx,%eax
  mov    0x18(%rdi),%edx
  or     $0xff000000,%eax
  mov    %eax,0x44(%rsp)
  mov    %edx,%ecx
  mov    %edx,%eax
  shl    $0x3,%edx
  shl    $0x6,%eax
  shl    $0x9,%ecx
  movzbl %dl,%edx
  and    $0xf80000,%ecx
  and    $0xf800,%eax
  or     %ecx,%eax
  or     %edx,%eax
  mov    0x1c(%rdi),%edx
  or     $0xff000000,%eax
  mov    %eax,0x48(%rsp)
  mov    %edx,%ecx
  mov    %edx,%eax
  shl    $0x3,%edx
  shl    $0x6,%eax
  shl    $0x9,%ecx
  movzbl %dl,%edx
  and    $0xf80000,%ecx
  and    $0xf800,%eax
  or     %ecx,%eax
  or     %edx,%eax
  mov    0x20(%rdi),%edx
  or     $0xff000000,%eax
  mov    %eax,0x4c(%rsp)
  mov    %edx,%eax
  mov    %edx,%ecx
  shl    $0x6,%eax
  and    $0xf800,%eax
  shl    $0x9,%ecx
  and    $0xf80000,%ecx
  shl    $0x3,%edx
  or     %ecx,%eax
  movzbl %dl,%edx
  or     %edx,%eax
  mov    0x24(%rdi),%edx
  or     $0xff000000,%eax
  mov    %eax,0x50(%rsp)
  mov    %edx,%ecx
  mov    %edx,%eax
  shl    $0x3,%edx
  shl    $0x6,%eax
  shl    $0x9,%ecx
  movzbl %dl,%edx
  and    $0xf80000,%ecx
  and    $0xf800,%eax
  or     %ecx,%eax
  or     %edx,%eax
  mov    0x28(%rdi),%edx
  or     $0xff000000,%eax
  mov    %eax,0x54(%rsp)
  mov    %edx,%ecx
  mov    %edx,%eax
  shl    $0x3,%edx
  shl    $0x6,%eax
  shl    $0x9,%ecx
  movzbl %dl,%edx
  and    $0xf80000,%ecx
  and    $0xf800,%eax
  or     %ecx,%eax
  or     %edx,%eax
  mov    0x2c(%rdi),%edx
  or     $0xff000000,%eax
  mov    %eax,0x58(%rsp)
  mov    %edx,%ecx
  mov    %edx,%eax
  shl    $0x3,%edx
  shl    $0x6,%eax
  shl    $0x9,%ecx
  movzbl %dl,%edx
  and    $0xf80000,%ecx
  and    $0xf800,%eax
  or     %ecx,%eax
  or     %edx,%eax
  mov    0x30(%rdi),%edx
  or     $0xff000000,%eax
  mov    %eax,0x5c(%rsp)
  mov    %edx,%eax
  mov    %edx,%ecx
  shl    $0x6,%eax
  and    $0xf800,%eax
  shl    $0x9,%ecx
  and    $0xf80000,%ecx
  shl    $0x3,%edx
  or     %ecx,%eax
  movzbl %dl,%edx
  or     %edx,%eax
  mov    0x34(%rdi),%edx
  or     $0xff000000,%eax
  mov    %eax,0x60(%rsp)
  mov    %edx,%ecx
  mov    %edx,%eax
  shl    $0x3,%edx
  shl    $0x6,%eax
  shl    $0x9,%ecx
  movzbl %dl,%edx
  and    $0xf80000,%ecx
  and    $0xf800,%eax
  or     %ecx,%eax
  or     %edx,%eax
  or     $0xff000000,%eax
  mov    %eax,0x64(%rsp)
  mov    0x38(%rdi),%edx
  mov    0xc(%rsp),%esi
  mov    %edx,%eax
  mov    %edx,%ecx
  shl    $0x3,%edx
  shl    $0x6,%eax
  shl    $0x9,%ecx
  movzbl %dl,%edx
  and    $0xf80000,%ecx
  and    $0xf800,%eax
  or     %ecx,%eax
  or     %edx,%eax
  mov    0x3c(%rdi),%edx
  mov    0x20(%rsp),%rdi
  or     $0xff000000,%eax
  mov    %eax,0x68(%rsp)
  mov    %edx,%ecx
  mov    %edx,%eax
  shl    $0x3,%edx
  shl    $0x6,%eax
  shl    $0x9,%ecx
  movzbl %dl,%edx
  and    $0xf80000,%ecx
  and    $0xf800,%eax
  or     %ecx,%eax
  lea    0x10(%rsp),%rcx
  or     %edx,%eax
  lea    0x30(%rsp),%rdx
  or     $0xff000000,%eax
  mov    %eax,0x6c(%rsp)
  call   <deindex_4bpp@plt>
  mov    %eax,%r12d
  test   %ebx,%ebx
  jne    L6
L39:
  mov    0x10(%rsp),%rdi
  lea    0x18(%rsp),%rcx
  mov    $0x8,%edx
  mov    %r12d,%esi
  call   <detile@plt>
  mov    0x18(%rsp),%rax
  mov    0x10(%rsp),%rdi
  mov    %rax,0x0(%rbp)
  call   <free@plt>
  mov    0x78(%rsp),%rax
  sub    %fs:0x28,%rax
  jne    L28
  sub    $0xffffffffffffff80,%rsp
  pop    %rbx
  pop    %rbp
  pop    %r12
  pop    %r13
  pop    %r14
  ret
  nopl   0x0(%rax,%rax,1)
L49:
  mov    $0x9000000,%ecx
  lea    0xc(%rsp),%rdx
  sub    %esi,%ecx
  lea    0x20(%rsp),%rsi
  call   <decompress@plt>
  jmp    L57
  nopl   0x0(%rax,%rax,1)
L6:
  mov    0x20(%rsp),%rdi
  call   <free@plt>
  jmp    L39
  nopl   0x0(%rax)
L51:
  mov    $0x9000000,%ecx
  lea    0x28(%rsp),%rsi
  xor    %edx,%edx
  sub    %r13d,%ecx
  call   <decompress@plt>
  mov    0x28(%rsp),%rdi
  jmp    L12
L28:
  call   <__stack_chk_fail@plt>
```

assistant: ```c
void extract_image(uint8_t *buffer, uint32_t imgAddr, uint32_t palAddr, int compImg, int compPal, uint32_t **out) {
  uint32_t destSize, srcSize, *pixels = NULL, *image = NULL;
  uint8_t *output = NULL, *offset = NULL;
  size_t i;
  offset = (uint8_t *)(buffer + (imgAddr - 0x8000000));
  srcSize = (1 << 24) - (imgAddr - 0x8000000);
  if (compImg) {
    decompress((const uint8_t *)offset, &output, &destSize, srcSize);
  } else {
    output = offset;
  }
  uint16_t *paletteGBA = NULL;
  uint8_t *paletteComp = (uint8_t *)((palAddr - 0x8000000) + buffer);
  srcSize = (1 << 24) - (palAddr - 0x8000000);
  if (compPal) {
    decompress((const uint8_t *)paletteComp, (uint8_t **)&paletteGBA, NULL, srcSize);
  } else {
    paletteGBA = (uint16_t *)paletteComp;
  }
  uint32_t paletteRGBA[16] = {};
  for (i = 0; i < 16; i++) {
    uint32_t r, g, b, a;
    r = ((paletteGBA[i] >> 0) & 0x1F) << (3);
    g = ((paletteGBA[i] >> 5) & 0x1F) << (3 + 8);
    b = ((paletteGBA[i] >> 10) & 0x1F) << (3 + 16);
    a = (i ? 0xFF : 0x0) << 24;
    paletteRGBA[i] = r | g | b | a;
  }
  int length = deindex_4bpp(output, destSize, paletteRGBA, &pixels);
  if (compImg)
    free(output);
  detile(pixels, length, 8, &image);
  *out = image;
  free(pixels);
}
```