#define NULL ((void *)0)
typedef unsigned long size_t; // Customize by platform.
typedef long intptr_t;
typedef unsigned long uintptr_t;
typedef long scalar_t__; // Either arithmetic or pointer type.
/* By default, we understand bool (as a convenience). */
typedef int bool;
#define false 0
#define true 1

/* Forward declarations */

/* Type definitions */

/* Variables and functions */
#define __NR_close 133
#define __NR_exit_group 132
#define __NR_mprotect 131
#define __NR_open 130
#define __NR_read 129
#define __NR_write 128
int op_close(unsigned int);
int op_exit_group(unsigned int);
int op_open(char const *);
int op_read(unsigned int, char *, unsigned int);
int op_write(unsigned int, char const *, unsigned int);
int kernel(unsigned int arg0, unsigned int arg1, unsigned int arg2,
           unsigned int arg3) {
  int ret = 0;
  switch (arg0) {
  case __NR_read:
    ret = op_read(arg1, (char *)((long)arg2), arg3);
    break;
  case __NR_write:
    ret = op_write(arg1, (const char *)((long)arg2), arg3);
    break;
  case __NR_open:
    ret = op_open((const char *)((long)arg1));
    break;
  case __NR_close:
    ret = op_close(arg1);
    break;
  case __NR_mprotect:
    ret = -1;
    break;
  case __NR_exit_group:
    ret = op_exit_group(arg1);
    break;
  default:
    ret = -1;
    break;
  }
  return ret;
}


x86 assembly (clang, -O0):
<kernel>:
push   %rbp
mov    %rsp,%rbp
sub    $0x20,%rsp
mov    %edi,-0x4(%rbp)
mov    %esi,-0x8(%rbp)
mov    %edx,-0xc(%rbp)
mov    %ecx,-0x10(%rbp)
movl   $0x0,-0x14(%rbp)
mov    -0x4(%rbp),%eax
add    $0xffffff80,%eax
mov    %eax,%ecx
mov    %rcx,-0x20(%rbp)
sub    $0x5,%eax
ja     1202 <kernel+0xb2>
mov    -0x20(%rbp),%rax
lea    0xe75(%rip),%rcx
movslq (%rcx,%rax,4),%rax
add    %rcx,%rax
jmp    *%rax
mov    -0x8(%rbp),%edi
mov    -0xc(%rbp),%eax
mov    %eax,%esi
mov    -0x10(%rbp),%edx
call   1070 <op_read@plt>
mov    %eax,-0x14(%rbp)
jmp    1209 <kernel+0xb9>
mov    -0x8(%rbp),%edi
mov    -0xc(%rbp),%eax
mov    %eax,%esi
mov    -0x10(%rbp),%edx
call   1040 <op_write@plt>
mov    %eax,-0x14(%rbp)
jmp    1209 <kernel+0xb9>
mov    -0x8(%rbp),%eax
mov    %eax,%edi
call   1060 <op_open@plt>
mov    %eax,-0x14(%rbp)
jmp    1209 <kernel+0xb9>
mov    -0x8(%rbp),%edi
call   1030 <op_close@plt>
mov    %eax,-0x14(%rbp)
jmp    1209 <kernel+0xb9>
movl   $0xffffffff,-0x14(%rbp)
jmp    1209 <kernel+0xb9>
mov    -0x8(%rbp),%edi
call   1050 <op_exit_group@plt>
mov    %eax,-0x14(%rbp)
jmp    1209 <kernel+0xb9>
movl   $0xffffffff,-0x14(%rbp)
mov    -0x14(%rbp),%eax
add    $0x20,%rsp
pop    %rbp
ret

x86 assembly (clang, -O2):
<kernel>:
add    $0xffffff80,%edi
cmp    $0x5,%edi
ja     118b <kernel+0x3b>
lea    0xea1(%rip),%rax
movslq (%rax,%rdi,4),%rdi
add    %rax,%rdi
jmp    *%rdi
mov    %edx,%eax
mov    %esi,%edi
mov    %rax,%rsi
mov    %ecx,%edx
jmp    1040 <op_write@plt>
mov    %edx,%eax
mov    %esi,%edi
mov    %rax,%rsi
mov    %ecx,%edx
jmp    1070 <op_read@plt>
mov    %esi,%edi
jmp    1060 <op_open@plt>
mov    $0xffffffff,%eax
ret
mov    %esi,%edi
jmp    1050 <op_exit_group@plt>
mov    %esi,%edi
jmp    1030 <op_close@plt>

LLVM IR (-O0):
define i32 @kernel(i32 %0, i32 %1, i32 %2, i32 %3) {
%5 = alloca i32
%6 = alloca i32
%7 = alloca i32
%8 = alloca i32
%9 = alloca i32
store i32 %0, i32* %5
store i32 %1, i32* %6
store i32 %2, i32* %7
store i32 %3, i32* %8
store i32 0, i32* %9
%10 = load i32, i32* %5
switch i32 %10, label %37 [
i32 129, label %11
i32 128, label %18
i32 130, label %25
i32 133, label %30
i32 131, label %33
i32 132, label %34
]
11: ; preds = %4
%12 = load i32, i32* %6
%13 = load i32, i32* %7
%14 = zext i32 %13 to i64
%15 = inttoptr i64 %14 to i8*
%16 = load i32, i32* %8
%17 = call i32 @op_read(i32 %12, i8* %15, i32 %16)
store i32 %17, i32* %9
br label %38
18: ; preds = %4
%19 = load i32, i32* %6
%20 = load i32, i32* %7
%21 = zext i32 %20 to i64
%22 = inttoptr i64 %21 to i8*
%23 = load i32, i32* %8
%24 = call i32 @op_write(i32 %19, i8* %22, i32 %23)
store i32 %24, i32* %9
br label %38
25: ; preds = %4
%26 = load i32, i32* %6
%27 = zext i32 %26 to i64
%28 = inttoptr i64 %27 to i8*
%29 = call i32 @op_open(i8* %28)
store i32 %29, i32* %9
br label %38
30: ; preds = %4
%31 = load i32, i32* %6
%32 = call i32 @op_close(i32 %31)
store i32 %32, i32* %9
br label %38
33: ; preds = %4
store i32 -1, i32* %9
br label %38
34: ; preds = %4
%35 = load i32, i32* %6
%36 = call i32 @op_exit_group(i32 %35)
store i32 %36, i32* %9
br label %38
37: ; preds = %4
store i32 -1, i32* %9
br label %38
38: ; preds = %37, %34, %33, %30, %25, %18, %11
%39 = load i32, i32* %9
ret i32 %39
}

LLVM IR (-O2):
define i32 @kernel(i32 %0, i32 %1, i32 %2, i32 %3) {
switch i32 %0, label %21 [
i32 129, label %5
i32 128, label %9
i32 130, label %13
i32 133, label %17
i32 132, label %19
]
5: ; preds = %4
%6 = zext i32 %2 to i64
%7 = inttoptr i64 %6 to i8*
%8 = tail call i32 @op_read(i32 %1, i8* %7, i32 %3)
br label %21
9: ; preds = %4
%10 = zext i32 %2 to i64
%11 = inttoptr i64 %10 to i8*
%12 = tail call i32 @op_write(i32 %1, i8* %11, i32 %3)
br label %21
13: ; preds = %4
%14 = zext i32 %1 to i64
%15 = inttoptr i64 %14 to i8*
%16 = tail call i32 @op_open(i8* %15)
br label %21
17: ; preds = %4
%18 = tail call i32 @op_close(i32 %1)
br label %21
19: ; preds = %4
%20 = tail call i32 @op_exit_group(i32 %1)
br label %21
21: ; preds = %4, %19, %17, %13, %9, %5
%22 = phi i32 [ %20, %19 ], [ %18, %17 ], [ %16, %13 ], [ %12, %9 ], [ %8, %5 ], [ -1, %4 ]
ret i32 %22
}