// File: /workspace/github_c_makefile_star2_O3/mikecat[P]x86_interpreter/read_pe.c
// Function: read_pe
int read_pe(uint32_t* eip_value, uint32_t* stack_size, pe_import_params* import_params, const char* filename) {
	size_t filesize = 0;
	uint8_t* filedata = read_whole_file(&filesize, filename);
	uint32_t newheader_offset;
	uint8_t* newheader;
	uint32_t num_section, optheader_size, section_table_size;
	uint8_t* optheader;
	uint32_t magic, entrypoint, image_base, stack_reserve;
	uint8_t* section_table;
	uint32_t i;
	if (filedata == 0) return 0;
	if (filesize < 64) {
		fprintf(stderr, "file size too small for PE header\n");
		free(filedata); return 0;
	}
	if (filedata[0] != 'M' || filedata[1] != 'Z') {
		fprintf(stderr, "not PE file\n");
		free(filedata); return 0;
	}
	newheader_offset = read_num(filedata + 60, 4);
	if (newheader_offset > filesize - 24) {
		fprintf(stderr, "file size too small for PE new header\n");
		free(filedata); return 0;
	}
	newheader = filedata + newheader_offset;
	if (newheader[0] != 'P' || newheader[1] != 'E' || newheader[2] != 0x00 || newheader[3] != 0x00) {
		fprintf(stderr, "wrong PE new header signature\n");
		free(filedata); return 0;
	}
	num_section = read_num(newheader + 6, 2);
	optheader_size = read_num(newheader + 20, 2);
	section_table_size = 40 * num_section;
	if (optheader_size > filesize || filesize - optheader_size < newheader_offset + 24) {
		fprintf(stderr, "file size too small for PE optional header\n");
		free(filedata); return 0;
	}
	if (optheader_size < 76) { /* TODO */
		fprintf(stderr, "PE optional header too small\n");
		free(filedata); return 0;
	}
	optheader = newheader + 24;
	magic = read_num(optheader + 0, 2);
	entrypoint = read_num(optheader + 16, 4);
	image_base = read_num(optheader + 28, 4);
	stack_reserve = read_num(optheader + 72, 4);
	if (magic == 0x20b) {
		fprintf(stderr, "unsupported 64-bit PE file detected\n");
		free(filedata); return 0;
	}
	if (UINT32_MAX - image_base < entrypoint) {
		fprintf(stderr, "PE entrypoint out of address space\n");
		free(filedata); return 0;
	}
	if (import_params != NULL) {
		uint32_t import_addr, import_size, iat_addr, iat_size;
		if (optheader_size >= 112) {
			import_addr = read_num(optheader + 104, 4);
			import_size = read_num(optheader + 108, 4);
		} else {
			import_addr = 0;
			import_size = 0;
		}
		if (optheader_size >= 200) {
			iat_addr = read_num(optheader + 192, 4);
			iat_size = read_num(optheader + 196, 4);
		} else {
			iat_addr = 0;
			iat_size = 0;
		}
		if (import_size > 0) {
			if (UINT32_MAX - image_base < import_addr ||
			UINT32_MAX - (image_base + import_addr) < import_size - 1) {
				fprintf(stderr, "PE import informaton out of address space\n");
				free(filedata); return 0;
			}
		}
		if (iat_size > 0) {
			if (UINT32_MAX - image_base < iat_addr ||
			UINT32_MAX - (image_base + iat_addr) < iat_size - 1) {
				fprintf(stderr, "PE import address table out of address space\n");
				free(filedata); return 0;
			}
		}
		import_params->image_base = image_base;
		import_params->import_addr = image_base + import_addr;
		import_params->import_size = import_size;
		import_params->iat_addr = image_base + iat_addr;
		import_params->iat_size = iat_size;
	}
	if (section_table_size > filesize || filesize - section_table_size < newheader_offset + 24 + optheader_size) {
		fprintf(stderr, "file size too small for PE section table\n");
		free(filedata); return 0;
	}
	section_table = optheader + optheader_size;
	for (i = 0; i < num_section; i++) {
		uint8_t* section_data = section_table + 40 * i;
		uint32_t size, addr, file_size, file_offset;
		uint32_t load_size;
		size = read_num(section_data + 8, 4);
		addr = read_num(section_data + 12, 4);
		file_size = read_num(section_data + 16, 4);
		file_offset = read_num(section_data + 20, 4);
		load_size = (file_offset == 0 ? 0 : (size < file_size ? size : file_size));
		if (UINT32_MAX - image_base < addr || (size > 0 && UINT32_MAX - (image_base + addr) < size - 1)) {
			fprintf(stderr, "PE section %"PRIu32" out of address space\n", i);
			free(filedata); return 0;
		}
		if (filesize - file_offset < load_size) {
			fprintf(stderr, "PE section %"PRIu32" out of file\n", i);
			free(filedata); return 0;
		}
		dmemory_allocate(image_base + addr, size);
		dmemory_write(filedata + file_offset, image_base + addr, load_size);
	}
	if (eip_value != NULL) *eip_value = image_base + entrypoint;
	if (stack_size != NULL) *stack_size = stack_reserve;
	free(filedata);
	return 1;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x58, %rsp
movq %rdx, %r12
movq %rsi, %rbx
movq %rdi, %r14
leaq 0x30(%rsp), %rdi
movq $0x0, (%rdi)
movq %rcx, %rsi
callq 0x9d8c
testq %rax, %rax
je 0xa4fd
movq %rax, %r13
movq 0x30(%rsp), %rax
cmpq $0x3f, %rax
jbe 0xa52f
cmpb $0x4d, (%r13)
jne 0xa51b
cmpb $0x5a, 0x1(%r13)
jne 0xa51b
leaq 0x3c(%r13), %rsi
xorl %ecx, %ecx
xorl %edx, %edx
movzbl (%rsi), %edi
shll %cl, %edi
orl %edi, %edx
addq $0x8, %rcx
incq %rsi
cmpq $0x20, %rcx
jne 0xa2d0
leaq -0x18(%rax), %rcx
cmpq %rdx, %rcx
jb 0xa6f5
cmpb $0x50, (%r13,%rdx)
jne 0xa504
leaq (%rdx,%r13), %r10
cmpb $0x45, 0x1(%r10)
jne 0xa504
cmpb $0x0, 0x2(%r10)
jne 0xa504
cmpb $0x0, 0x3(%r10)
jne 0xa504
movzwl 0x14(%r10), %esi
movq %rax, %rcx
subq %rsi, %rcx
jb 0xa525
movl %edx, %edi
addl $0x18, %edi
cmpq %rdi, %rcx
jb 0xa525
cmpl $0x4b, %esi
jbe 0xa6fc
movq %r14, 0x38(%rsp)
movq %rbx, 0x40(%rsp)
movzwl 0x6(%r10), %r8d
leal (,%r8,8), %ecx
leal (%rcx,%rcx,4), %ecx
movl %ecx, 0x18(%rsp)
movzbl 0x18(%r10), %r11d
movzbl 0x19(%r10), %ebp
shll $0x8, %ebp
leaq 0x28(%r10), %rbx
xorl %ecx, %ecx
xorl %r15d, %r15d
movzbl (%rbx), %r14d
shll %cl, %r14d
orl %r14d, %r15d
addq $0x8, %rcx
incq %rbx
cmpq $0x20, %rcx
jne 0xa37e
movl %r15d, 0x14(%rsp)
leaq 0x34(%r10), %r14
xorl %ecx, %ecx
xorl %ebx, %ebx
movzbl (%r14), %r15d
shll %cl, %r15d
orl %r15d, %ebx
addq $0x8, %rcx
incq %r14
cmpq $0x20, %rcx
jne 0xa3a2
leaq 0x60(%r10), %r14
xorl %ecx, %ecx
xorl %r9d, %r9d
movzbl (%r14), %r15d
shll %cl, %r15d
orl %r15d, %r9d
addq $0x8, %rcx
incq %r14
cmpq $0x20, %rcx
jne 0xa3c2
movl %r9d, 0x24(%rsp)
orl %r11d, %ebp
cmpl $0x20b, %ebp            # imm = 0x20B
je 0xa703
movl %ebx, %ecx
notl %ecx
movl %ecx, 0x4(%rsp)
cmpl %ecx, 0x14(%rsp)
ja 0xa70a
testq %r12, %r12
movq %r13, 0x8(%rsp)
je 0xa55a
cmpl $0x70, %esi
jb 0xa50e
leaq 0x80(%r10), %r14
xorl %ecx, %ecx
xorl %r11d, %r11d
movzbl (%r14), %ebp
shll %cl, %ebp
orl %ebp, %r11d
addq $0x8, %rcx
incq %r14
cmpq $0x20, %rcx
jne 0xa422
leaq 0x84(%r10), %r14
xorl %ecx, %ecx
xorl %ebp, %ebp
movzbl (%r14), %r15d
shll %cl, %r15d
orl %r15d, %ebp
addq $0x8, %rcx
incq %r14
cmpq $0x20, %rcx
jne 0xa443
xorl %r15d, %r15d
movl $0x0, %r14d
cmpl $0xc8, %esi
jb 0xa4b6
leaq 0xd8(%r10), %r15
xorl %ecx, %ecx
xorl %r14d, %r14d
movzbl (%r15), %r13d
shll %cl, %r13d
orl %r13d, %r14d
addq $0x8, %rcx
incq %r15
cmpq $0x20, %rcx
jne 0xa477
addq $0xdc, %r10
xorl %ecx, %ecx
xorl %r15d, %r15d
movzbl (%r10), %r13d
shll %cl, %r13d
orl %r13d, %r15d
addq $0x8, %rcx
incq %r10
cmpq $0x20, %rcx
jne 0xa49a
movq 0x8(%rsp), %r13
testl %ebp, %ebp
je 0xa4d8
cmpl 0x4(%rsp), %r11d
ja 0xa745
leal (%r11,%rbx), %ecx
movl %ebp, %r10d
negl %r10d
cmpl %r10d, %ecx
ja 0xa745
testl %r15d, %r15d
je 0xa539
cmpl 0x4(%rsp), %r14d
ja 0xa4f3
leal (%r14,%rbx), %ecx
movl %r15d, %r10d
negl %r10d
cmpl %r10d, %ecx
jbe 0xa53c
callq 0x1a62
jmp 0xa74a
xorl %ebp, %ebp
jmp 0xa754
callq 0x1a1e
jmp 0xa74a
xorl %r11d, %r11d
xorl %ebp, %ebp
xorl %r15d, %r15d
xorl %r14d, %r14d
jmp 0xa53c
callq 0x19fc
jmp 0xa74a
callq 0x1b0c
jmp 0xa74a
callq 0x1b50
jmp 0xa74a
xorl %r15d, %r15d
movl %ebx, (%r12)
addl %ebx, %r11d
movl %r11d, 0x4(%r12)
movl %ebp, 0x8(%r12)
addl %ebx, %r14d
movl %r14d, 0xc(%r12)
movl %r15d, 0x10(%r12)
movl 0x18(%rsp), %ecx
subq %rcx, %rax
jb 0xa6ee
addl %esi, %edi
cmpq %rdi, %rax
jb 0xa6ee
movq %rbx, 0x28(%rsp)
testl %r8d, %r8d
je 0xa6bd
movl %r8d, %eax
movq %rax, 0x48(%rsp)
addq 0x8(%rsp), %rsi
leaq (%rdx,%rsi), %r9
addq $0x20, %r9
leaq (%rdx,%rsi), %r10
addq $0x24, %r10
leaq (%rdx,%rsi), %r12
addq $0x28, %r12
leaq (%rdx,%rsi), %r15
addq $0x2c, %r15
xorl %edx, %edx
movq %r9, %rax
xorl %ecx, %ecx
xorl %esi, %esi
movzbl (%rax), %edi
shll %cl, %edi
orl %edi, %esi
addq $0x8, %rcx
incq %rax
cmpq $0x20, %rcx
jne 0xa5b6
xorl %ecx, %ecx
movq %r10, %rax
xorl %r13d, %r13d
movq 0x28(%rsp), %r11
movzbl (%rax), %edi
shll %cl, %edi
orl %edi, %r13d
addq $0x8, %rcx
incq %rax
cmpq $0x20, %rcx
jne 0xa5d7
xorl %ecx, %ecx
movq %r12, %rax
xorl %ebp, %ebp
movzbl (%rax), %edi
shll %cl, %edi
orl %edi, %ebp
addq $0x8, %rcx
incq %rax
cmpq $0x20, %rcx
jne 0xa5f3
xorl %ecx, %ecx
movq %r15, %r8
xorl %eax, %eax
movzbl (%r8), %edi
shll %cl, %edi
orl %edi, %eax
addq $0x8, %rcx
incq %r8
cmpq $0x20, %rcx
jne 0xa60e
cmpl %ebp, %esi
cmovbl %esi, %ebp
testl %eax, %eax
cmovel %eax, %ebp
cmpl 0x4(%rsp), %r13d
ja 0xa711
testl %esi, %esi
je 0xa64c
leal (%r11,%r13), %ecx
movl %esi, %edi
negl %edi
cmpl %edi, %ecx
ja 0xa711
movq 0x30(%rsp), %rcx
movl %eax, %r14d
subq %r14, %rcx
movl %ebp, %eax
cmpq %rax, %rcx
jb 0xa724
addl %r11d, %r13d
movl %r13d, %edi
movq %rdx, 0x18(%rsp)
movq %r15, 0x50(%rsp)
movq %r9, %r15
movq %r10, %rbx
callq 0x6caf
addq 0x8(%rsp), %r14
movq %r14, %rdi
movl %r13d, %esi
movl %ebp, %edx
callq 0x6b71
movq %rbx, %r10
movq %r15, %r9
movq 0x50(%rsp), %r15
movq 0x18(%rsp), %rdx
incq %rdx
addq $0x28, %r9
addq $0x28, %r10
addq $0x28, %r12
addq $0x28, %r15
cmpq 0x48(%rsp), %rdx
jne 0xa5af
movq 0x38(%rsp), %rax
testq %rax, %rax
je 0xa6d2
movq 0x28(%rsp), %rcx
addl 0x14(%rsp), %ecx
movl %ecx, (%rax)
movl $0x1, %ebp
movq 0x40(%rsp), %rax
testq %rax, %rax
movq 0x8(%rsp), %r13
movl 0x24(%rsp), %ecx
je 0xa74c
movl %ecx, (%rax)
jmp 0xa74c
callq 0x1a84
jmp 0xa74a
callq 0x1b2e
jmp 0xa74a
callq 0x1aea
jmp 0xa74a
callq 0x1ac8
jmp 0xa74a
callq 0x1aa6
jmp 0xa74a
movq 0x88e0(%rip), %rax      # 0x12ff8
movq (%rax), %rdi
leaq 0x3bfa(%rip), %rsi      # 0xe31c
jmp 0xa735
movq 0x88cd(%rip), %rax      # 0x12ff8
movq (%rax), %rdi
leaq 0x3c0b(%rip), %rsi      # 0xe340
xorl %ebp, %ebp
xorl %eax, %eax
callq 0x10d0
movq 0x8(%rsp), %r13
jmp 0xa74c
callq 0x1a40
xorl %ebp, %ebp
movq %r13, %rdi
callq 0x1030
movl %ebp, %eax
addq $0x58, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
nopl (%rax)