// File: ksherlock[P]wdc-utils/link.cpp
// Function: one_module(std::vector<unsigned char, std::allocator<unsigned char>> const&, std::vector<unsigned char, std::allocator<unsigned char>> const&, std::vector<unsigned char, std::allocator<unsigned char>> const&, std::set<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>*)
void one_module(const std::vector<uint8_t> &data, 
	const std::vector<uint8_t> &section_data, 
	const std::vector<uint8_t> &symbol_data,
	std::set<std::string> *local_undefined = nullptr) {

	std::array<int, 256> remap_section;


	std::fill(remap_section.begin(), remap_section.end(), -1);
	remap_section[SECT_PAGE0] = SECT_PAGE0;
	remap_section[SECT_CODE] = SECT_CODE;
	remap_section[SECT_KDATA] = SECT_KDATA;
	remap_section[SECT_DATA] = SECT_DATA;
	remap_section[SECT_UDATA] = SECT_UDATA;

	std::vector<section> local_sections = read_sections(section_data);
	std::vector<symbol> local_symbols = read_symbols(symbol_data);



	// convert local sections to global 
	for (auto &s : local_sections) {
		//printf("section %20s %d\n", s.name.c_str(), s.number);

		if (s.number <= SECT_UDATA) {
			sections[s.number].size += s.size; // for page0 / udata sections.
			continue;
		}


		// todo -- should install section name as global symbol?

		auto iter = section_map.find(s.name);
		if (iter == section_map.end()) {

			int virtual_section = sections.size();
			remap_section[s.number] = virtual_section;
			s.number = virtual_section;

			if (!(s.flags & SEC_NONAME)) {
				/* generate an _BEG_name_ and _END_name */

				symbol sym;

				sym.name = "_BEG_" + s.name;
				upper_case(sym.name);
				sym.section = virtual_section;
				sym.type = S_REL; // check if section has offset?
				sym.flags = SF_DEF | SF_GBL;


				auto iter = symbol_map.find(sym.name);
				if (iter == symbol_map.end()) {
					symbol_map.emplace(sym.name, symbols.size());
					symbols.emplace_back(std::move(sym));
				} else {
					// duplicate label error...
				}


/*
				// add entry for name? or handle via undefined symbol lookup below?
				handled at end if symbol undeinfed.

				sym.name = s.name;
				sym.section = virtual_section;
				sym.type = S_REL;
				sym.flags = SF_DEF | SF_GBL;

				iter = symbol_map.find(sym.name);
				if (iter == symbol_map.end()) {
					symbol_map.emplace(sym.name, symbols.size());
					symbols.emplace_back(std::move(sym));
				} else {
					// duplicate label error...
				}
*/

				sym.name = "_END_" + s.name;
				upper_case(sym.name);

				sym.section = symbols.size();
				sym.type = S_UND;
				sym.flags = 0;

				iter = symbol_map.find(sym.name);
				if (iter == symbol_map.end()) {
					s.end_symbol = sym.section;
					symbol_map.emplace(sym.name, sym.section);
					symbols.emplace_back(std::move(sym));	
				} else {
					// duplicate label...
				}



			}

			sections.emplace_back(s);
			section_map.emplace(s.name, virtual_section);

		} else {
			auto &ss = sections[iter->second];
			assert(ss.flags == s.flags); // check org????
			remap_section[s.number] = iter->second;
			s.number = iter->second;

			// update size (for ref-only sections)
			ss.size += s.size;
		}
	}



	// convert local symbols to global.
	for (auto &s : local_symbols) {

		if (flags.v) {
			const char *status = "";
			if (s.type == S_UND) status = "extern";
			else if (s.flags & SF_GBL) status = "public";
			else status = "private";
			fprintf(stderr, "  %-20s [%s]\n", s.name.c_str(), status);
		}

		if (s.type == S_UND) {


			auto iter = symbol_map.find(s.name);
			if (iter == symbol_map.end()) {
				s.section = symbols.size();
				symbol_map.emplace(s.name, s.section);
				symbols.emplace_back(s);
				undefined_symbols.emplace(s.name);

				fprintf(stderr, "Adding %s to undefined symbols\n", s.name.c_str());
			}
			else {
				// already exists... 
				const auto &ss = symbols[iter->second];
				/* if (ss.type != S_UND) */
				// always copy over since s.section is a big deal.
				s = ss;
			}

			if (local_undefined) {
				if (s.type == S_UND) local_undefined->emplace(s.name);
			}
			continue;
		}

		// remap and fudge the offset.
		if ((s.type & 0x0f) == S_REL) {
			int virtual_section = remap_section[s.section];
			assert(virtual_section != -1);
			s.section = virtual_section;
			s.offset += sections[virtual_section].data.size();
		} else {
			s.section = -1;
		}



		constexpr const unsigned mask = SF_GBL | SF_DEF;
		if ((s.flags & mask) == mask) {

			auto iter = symbol_map.find(s.name);

			if (iter == symbol_map.end()) {
				unsigned tmp = symbols.size();
				symbol_map.emplace(s.name, tmp);
				symbols.emplace_back(s);
			} else {
				auto &ss = symbols[iter->second];

				// if it was undefined, define it!
				if (ss.type == S_UND) {
					ss = s;
					undefined_symbols.erase(s.name);
				}
				else {
					// ok if symbols are identical..
					if (ss.type != s.type || ss.flags != s.flags || ss.section != s.section || ss.offset != s.offset) {
						warnx("Duplicate label %s", s.name.c_str());
						flags.errors++;
					} 
				}
			}

		}

	}

	// set it here. sections may be resized above.
	int current_section = SECT_CODE;
	std::vector<uint8_t> *data_ptr = &sections[current_section].data;


	auto iter = data.begin();
	for(;;) {
		uint8_t op = read_8(iter);
		if (op == REC_END) return;

		if (op < 0xf0) {
			data_ptr->insert(data_ptr->end(), iter, iter + op);
			iter += op;
			continue;
		}

		switch(op) {
			case REC_SPACE: {
				uint16_t count = read_16(iter);
				data_ptr->insert(data_ptr->end(), count, 0);
				break;
			}

			case REC_SECT: {
				/* switch sections */
				uint8_t s = read_8(iter);
				current_section = remap_section[s];
				assert(current_section > 0 && current_section < sections.size());

				data_ptr = &sections[current_section].data;
				break;
			}

			case REC_ORG: {
				assert(!"ORG not supported.");
				break;
			}

			case REC_RELEXP:
			case REC_EXPR: {

				expression e;
				e.relative = op == REC_RELEXP;
				e.section = current_section;

				e.offset =  data_ptr->size();
				e.size = read_8(iter);


				data_ptr->insert(data_ptr->end(), e.size, 0);

				int reduced_size = 0;
				/**/
				for(;;) {
					op = read_8(iter);
					if (op == OP_END) break;

					switch(op) {
						case OP_VAL: {
							reduced_size++;
							uint32_t offset = read_32(iter);
							e.stack.emplace_back(op, offset);
							break;
						}
						case OP_SYM: {
							reduced_size++;
							uint16_t symbol = read_16(iter);
							assert(symbol < local_symbols.size());
							auto &s = local_symbols[symbol];
							switch (s.type & 0x0f) {
								case S_UND:
									// S_UND indicates it's still undefined globally.
									e.stack.emplace_back(OP_SYM, 0, s.section); /* section is actually a symbol number */
									e.undefined = true;
									break;

								case S_REL:
									e.stack.emplace_back(OP_LOC, s.offset, s.section);
									break;

								case S_ABS:
									e.stack.emplace_back(OP_VAL, s.offset);
									break;

								default:
									assert(!"unsupported symbol flags.");
							}
							break;
						}
						case OP_LOC: {
							reduced_size++;
							uint8_t section = read_8(iter);
							uint32_t offset = read_32(iter);
							int real_section = remap_section[section];
							assert(real_section >= 0);
							e.stack.emplace_back(op, offset, real_section);
							break;
						}
						// operations..
						//unary
						case OP_NOT:
						case OP_NEG:
						case OP_FLP:
							e.stack.emplace_back(op);
							break;
						// binary
						case OP_EXP:
						case OP_MUL:
						case OP_DIV:
						case OP_MOD:
						case OP_SHR:
						case OP_SHL:
						case OP_ADD:
						case OP_SUB:
						case OP_AND:
						case OP_OR:
						case OP_XOR:
						case OP_EQ:
						case OP_GT:
						case OP_LT:
						case OP_UGT:
						case OP_ULT:
							reduced_size--;
							e.stack.emplace_back(op);
							break;
						default:
							assert(!"unsupported expression opcode.");
					}
				}

				if (reduced_size != 1) {
					expr_error(true, e, "Malformed expression");
				}
				sections[current_section].expressions.emplace_back(std::move(e));
				break;
			}


			case REC_LINE: break;
			case REC_DEBUG: {
				uint16_t size = read_16(iter);
				iter += size;
				break;		
			}

		}
	}
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x880, %rsp            # imm = 0x880
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movq %rcx, -0x20(%rbp)
leaq -0x420(%rbp), %rdi
movq %rdi, -0x718(%rbp)
callq 0xa140
movq -0x718(%rbp), %rdi
movq %rax, -0x720(%rbp)
callq 0xa160
movq -0x720(%rbp), %rdi
movq %rax, %rsi
movl $0xffffffff, -0x424(%rbp) # imm = 0xFFFFFFFF
leaq -0x424(%rbp), %rdx
callq 0xa110
movq -0x718(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0xa190
movq -0x718(%rbp), %rdi
movl $0x0, (%rax)
movl $0x1, %esi
callq 0xa190
movq -0x718(%rbp), %rdi
movl $0x1, (%rax)
movl $0x2, %esi
callq 0xa190
movq -0x718(%rbp), %rdi
movl $0x2, (%rax)
movl $0x3, %esi
callq 0xa190
movq -0x718(%rbp), %rdi
movl $0x3, (%rax)
movl $0x4, %esi
callq 0xa190
movl $0x4, (%rax)
movq -0x10(%rbp), %rsi
leaq -0x440(%rbp), %rdi
callq 0x3ab0
movq -0x18(%rbp), %rsi
leaq -0x458(%rbp), %rdi
callq 0x3c50
jmp 0x4185
leaq -0x440(%rbp), %rax
movq %rax, -0x470(%rbp)
movq -0x470(%rbp), %rdi
callq 0x9d70
movq %rax, -0x478(%rbp)
movq -0x470(%rbp), %rdi
callq 0x9da0
movq %rax, -0x480(%rbp)
leaq -0x478(%rbp), %rdi
leaq -0x480(%rbp), %rsi
callq 0x9dd0
testb $0x1, %al
jne 0x41d5
jmp 0x4708
leaq -0x478(%rbp), %rdi
callq 0x9e10
movq %rax, -0x488(%rbp)
movq -0x488(%rbp), %rax
cmpl $0x4, 0x2c(%rax)
ja 0x4245
movq -0x488(%rbp), %rax
movl 0x28(%rax), %eax
movl %eax, -0x724(%rbp)
movq -0x488(%rbp), %rax
movl 0x2c(%rax), %eax
movl %eax, %esi
leaq 0x3b1c8(%rip), %rdi     # 0x3f3e0
callq 0xa1c0
movl -0x724(%rbp), %ecx
addl 0x28(%rax), %ecx
movl %ecx, 0x28(%rax)
jmp 0x46f7
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x460(%rbp)
movl %eax, -0x464(%rbp)
jmp 0x54a0
movq -0x488(%rbp), %rsi
leaq 0x3b155(%rip), %rdi     # 0x3f3a8
callq 0xa1e0
movq %rax, -0x730(%rbp)
jmp 0x4261
movq -0x730(%rbp), %rax
movq %rax, -0x490(%rbp)
leaq 0x3b132(%rip), %rdi     # 0x3f3a8
callq 0xa240
movq %rax, -0x498(%rbp)
leaq -0x490(%rbp), %rdi
leaq -0x498(%rbp), %rsi
callq 0xa210
testb $0x1, %al
jne 0x429e
jmp 0x4632
leaq 0x3b13b(%rip), %rdi     # 0x3f3e0
callq 0xa270
movl %eax, -0x49c(%rbp)
movl -0x49c(%rbp), %eax
movl %eax, -0x734(%rbp)
movq -0x488(%rbp), %rax
movl 0x2c(%rax), %eax
movl %eax, %esi
leaq -0x420(%rbp), %rdi
callq 0xa190
movl -0x734(%rbp), %ecx
movl %ecx, (%rax)
movl -0x49c(%rbp), %ecx
movq -0x488(%rbp), %rax
movl %ecx, 0x2c(%rax)
movq -0x488(%rbp), %rax
movzbl 0x20(%rax), %eax
andl $0x40, %eax
cmpl $0x0, %eax
jne 0x45d5
leaq -0x4d0(%rbp), %rdi
callq 0x9bb0
movq -0x488(%rbp), %rdx
leaq 0x26f47(%rip), %rsi     # 0x2b264
leaq -0x4f0(%rbp), %rdi
callq 0xa2a0
jmp 0x432b
leaq -0x4d0(%rbp), %rdi
movq %rdi, -0x740(%rbp)
leaq -0x4f0(%rbp), %rsi
movq %rsi, -0x748(%rbp)
callq 0x33f0
movq -0x748(%rbp), %rdi
callq 0x31f0
movq -0x740(%rbp), %rdi
callq 0x4030
jmp 0x4366
movl -0x49c(%rbp), %eax
movl %eax, -0x4a8(%rbp)
movb $0x2, -0x4b0(%rbp)
movb $0x3, -0x4af(%rbp)
leaq 0x3b071(%rip), %rdi     # 0x3f3f8
leaq -0x4d0(%rbp), %rsi
callq 0xa1e0
movq %rax, -0x750(%rbp)
jmp 0x439c
movq -0x750(%rbp), %rax
movq %rax, -0x4f8(%rbp)
leaq 0x3b047(%rip), %rdi     # 0x3f3f8
callq 0xa240
movq %rax, -0x500(%rbp)
leaq -0x4f8(%rbp), %rdi
leaq -0x500(%rbp), %rsi
callq 0xa210
testb $0x1, %al
jne 0x43d9
jmp 0x4480
leaq 0x3b050(%rip), %rdi     # 0x3f430
callq 0xa400
movq %rax, -0x508(%rbp)
leaq 0x3b005(%rip), %rdi     # 0x3f3f8
leaq -0x4d0(%rbp), %rsi
leaq -0x508(%rbp), %rdx
callq 0xa3b0
movb %dl, -0x759(%rbp)
movq %rax, -0x758(%rbp)
jmp 0x4415
movb -0x759(%rbp), %al
movq -0x758(%rbp), %rcx
movq %rcx, -0x518(%rbp)
movb %al, -0x510(%rbp)
leaq 0x3affa(%rip), %rdi     # 0x3f430
leaq -0x4d0(%rbp), %rsi
callq 0x9bf0
jmp 0x4444
jmp 0x4482
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x460(%rbp)
movl %eax, -0x464(%rbp)
jmp 0x5494
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x460(%rbp)
movl %eax, -0x464(%rbp)
leaq -0x4d0(%rbp), %rdi
callq 0x9c70
jmp 0x5494
jmp 0x4482
movq -0x488(%rbp), %rdx
leaq 0x26dda(%rip), %rsi     # 0x2b26a
leaq -0x538(%rbp), %rdi
callq 0xa2a0
jmp 0x449e
leaq -0x4d0(%rbp), %rdi
movq %rdi, -0x768(%rbp)
leaq -0x538(%rbp), %rsi
movq %rsi, -0x770(%rbp)
callq 0x33f0
movq -0x770(%rbp), %rdi
callq 0x31f0
movq -0x768(%rbp), %rdi
callq 0x4030
jmp 0x44d9
leaq 0x3af50(%rip), %rdi     # 0x3f430
callq 0xa400
movl %eax, -0x4a8(%rbp)
movb $0x0, -0x4b0(%rbp)
movb $0x0, -0x4af(%rbp)
leaq 0x3aef8(%rip), %rdi     # 0x3f3f8
leaq -0x4d0(%rbp), %rsi
callq 0xa1e0
movq %rax, -0x778(%rbp)
jmp 0x4515
movq -0x778(%rbp), %rax
movq %rax, -0x540(%rbp)
movq -0x540(%rbp), %rax
movq %rax, -0x4f8(%rbp)
leaq 0x3aec0(%rip), %rdi     # 0x3f3f8
callq 0xa240
movq %rax, -0x548(%rbp)
leaq -0x4f8(%rbp), %rdi
leaq -0x548(%rbp), %rsi
callq 0xa210
testb $0x1, %al
jne 0x455d
jmp 0x45c7
leaq -0x4a8(%rbp), %rdx
movl -0x4a8(%rbp), %ecx
movq -0x488(%rbp), %rax
movl %ecx, 0x60(%rax)
leaq 0x3ae7d(%rip), %rdi     # 0x3f3f8
leaq -0x4d0(%rbp), %rsi
callq 0xa430
movb %dl, -0x781(%rbp)
movq %rax, -0x780(%rbp)
jmp 0x4596
movb -0x781(%rbp), %al
movq -0x780(%rbp), %rcx
movq %rcx, -0x558(%rbp)
movb %al, -0x550(%rbp)
leaq 0x3ae79(%rip), %rdi     # 0x3f430
leaq -0x4d0(%rbp), %rsi
callq 0x9bf0
jmp 0x45c5
jmp 0x45c9
jmp 0x45c9
leaq -0x4d0(%rbp), %rdi
callq 0x9c70
movq -0x488(%rbp), %rsi
leaq 0x3adfd(%rip), %rdi     # 0x3f3e0
callq 0xa480
jmp 0x45ea
movq -0x488(%rbp), %rsi
leaq 0x3adb0(%rip), %rdi     # 0x3f3a8
leaq -0x49c(%rbp), %rdx
callq 0xa430
movb %dl, -0x791(%rbp)
movq %rax, -0x790(%rbp)
jmp 0x4613
movb -0x791(%rbp), %al
movq -0x790(%rbp), %rcx
movq %rcx, -0x568(%rbp)
movb %al, -0x560(%rbp)
jmp 0x46f5
leaq -0x490(%rbp), %rdi
callq 0xa500
movslq 0x20(%rax), %rsi
leaq 0x3ad97(%rip), %rdi     # 0x3f3e0
callq 0xa1c0
movq %rax, -0x570(%rbp)
movq -0x570(%rbp), %rax
movzbl 0x20(%rax), %eax
movq -0x488(%rbp), %rcx
movzbl 0x20(%rcx), %ecx
cmpl %ecx, %eax
jne 0x4671
jmp 0x4690
leaq 0x26bf8(%rip), %rdi     # 0x2b270
leaq 0x26c05(%rip), %rsi     # 0x2b284
movl $0x209, %edx            # imm = 0x209
leaq 0x26c02(%rip), %rcx     # 0x2b28d
callq 0x3220
leaq -0x490(%rbp), %rdi
callq 0xa500
movl 0x20(%rax), %eax
movl %eax, -0x798(%rbp)
movq -0x488(%rbp), %rax
movl 0x2c(%rax), %eax
movl %eax, %esi
leaq -0x420(%rbp), %rdi
callq 0xa190
movl -0x798(%rbp), %ecx
movl %ecx, (%rax)
leaq -0x490(%rbp), %rdi
callq 0xa500
movl 0x20(%rax), %ecx
movq -0x488(%rbp), %rax
movl %ecx, 0x2c(%rax)
movq -0x488(%rbp), %rax
movl 0x28(%rax), %ecx
movq -0x570(%rbp), %rax
addl 0x28(%rax), %ecx
movl %ecx, 0x28(%rax)
jmp 0x46f7
leaq -0x478(%rbp), %rdi
callq 0xa070
jmp 0x41b9
leaq -0x458(%rbp), %rax
movq %rax, -0x578(%rbp)
movq -0x578(%rbp), %rdi
callq 0xa530
movq %rax, -0x580(%rbp)
movq -0x578(%rbp), %rdi
callq 0xa560
movq %rax, -0x588(%rbp)
leaq -0x580(%rbp), %rdi
leaq -0x588(%rbp), %rsi
callq 0xa590
testb $0x1, %al
jne 0x4758
jmp 0x4c97
leaq -0x580(%rbp), %rdi
callq 0xa5d0
movq %rax, -0x590(%rbp)
testb $0x1, 0x3abce(%rip)     # 0x3f340
je 0x4815
leaq 0x27257(%rip), %rax     # 0x2b9d6
movq %rax, -0x598(%rbp)
movq -0x590(%rbp), %rax
movzbl 0x20(%rax), %eax
cmpl $0x0, %eax
jne 0x47a6
leaq 0x26b73(%rip), %rax     # 0x2b310
movq %rax, -0x598(%rbp)
jmp 0x47d9
movq -0x590(%rbp), %rax
movzbl 0x21(%rax), %eax
andl $0x1, %eax
cmpl $0x0, %eax
je 0x47c9
leaq 0x26b57(%rip), %rax     # 0x2b317
movq %rax, -0x598(%rbp)
jmp 0x47d7
leaq 0x26b4e(%rip), %rax     # 0x2b31e
movq %rax, -0x598(%rbp)
jmp 0x47d9
movq 0x3a7f0(%rip), %rax     # 0x3efd0
movq (%rax), %rax
movq %rax, -0x7a0(%rbp)
movq -0x590(%rbp), %rdi
callq 0x3130
movq -0x7a0(%rbp), %rdi
movq %rax, %rdx
movq -0x598(%rbp), %rcx
leaq 0x26b18(%rip), %rsi     # 0x2b326
movb $0x0, %al
callq 0x3470
movq -0x590(%rbp), %rax
movzbl 0x20(%rax), %eax
cmpl $0x0, %eax
jne 0x49f6
movq -0x590(%rbp), %rsi
leaq 0x3abc1(%rip), %rdi     # 0x3f3f8
callq 0xa1e0
movq %rax, -0x7a8(%rbp)
jmp 0x4845
movq -0x7a8(%rbp), %rax
movq %rax, -0x5a0(%rbp)
leaq 0x3ab9e(%rip), %rdi     # 0x3f3f8
callq 0xa240
movq %rax, -0x5a8(%rbp)
leaq -0x5a0(%rbp), %rdi
leaq -0x5a8(%rbp), %rsi
callq 0xa210
testb $0x1, %al
jne 0x4882
jmp 0x4965
leaq 0x3aba7(%rip), %rdi     # 0x3f430
callq 0xa400
movl %eax, %ecx
movq -0x590(%rbp), %rax
movl %ecx, 0x28(%rax)
movq -0x590(%rbp), %rsi
movq %rsi, %rdx
addq $0x28, %rdx
leaq 0x3ab49(%rip), %rdi     # 0x3f3f8
callq 0xa430
movb %dl, -0x7b1(%rbp)
movq %rax, -0x7b0(%rbp)
jmp 0x48c3
movb -0x7b1(%rbp), %al
movq -0x7b0(%rbp), %rcx
movq %rcx, -0x5b8(%rbp)
movb %al, -0x5b0(%rbp)
movq -0x590(%rbp), %rsi
leaq 0x3ab45(%rip), %rdi     # 0x3f430
callq 0xa5f0
jmp 0x48f2
movq -0x590(%rbp), %rsi
leaq 0x3ab48(%rip), %rdi     # 0x3f448
callq 0xa670
movb %dl, -0x7c1(%rbp)
movq %rax, -0x7c0(%rbp)
jmp 0x4914
movb -0x7c1(%rbp), %al
movq -0x7c0(%rbp), %rcx
movq %rcx, -0x5c8(%rbp)
movb %al, -0x5c0(%rbp)
movq 0x3a69b(%rip), %rax     # 0x3efd0
movq (%rax), %rax
movq %rax, -0x7d0(%rbp)
movq -0x590(%rbp), %rdi
callq 0x3130
movq -0x7d0(%rbp), %rdi
movq %rax, %rdx
leaq 0x269d8(%rip), %rsi     # 0x2b334
movb $0x0, %al
callq 0x3470
jmp 0x499f
leaq -0x5a0(%rbp), %rdi
callq 0xa500
movslq 0x20(%rax), %rsi
leaq 0x3aab4(%rip), %rdi     # 0x3f430
callq 0x9fb0
movq %rax, -0x5d0(%rbp)
movq -0x5d0(%rbp), %rsi
movq -0x590(%rbp), %rdi
callq 0xa6c0
jmp 0x499d
jmp 0x499f
cmpq $0x0, -0x20(%rbp)
je 0x49f1
movq -0x590(%rbp), %rax
movzbl 0x20(%rax), %eax
cmpl $0x0, %eax
jne 0x49ef
movq -0x20(%rbp), %rdi
movq -0x590(%rbp), %rsi
callq 0xa670
movb %dl, -0x7d9(%rbp)
movq %rax, -0x7d8(%rbp)
jmp 0x49d5
movb -0x7d9(%rbp), %al
movq -0x7d8(%rbp), %rcx
movq %rcx, -0x5e0(%rbp)
movb %al, -0x5d8(%rbp)
jmp 0x49f1
jmp 0x4c86
movq -0x590(%rbp), %rax
movzbl 0x20(%rax), %eax
andl $0xf, %eax
cmpl $0x2, %eax
jne 0x4a9a
movq -0x590(%rbp), %rax
movslq 0x28(%rax), %rsi
leaq -0x420(%rbp), %rdi
callq 0xa190
movl (%rax), %eax
movl %eax, -0x5e4(%rbp)
cmpl $-0x1, -0x5e4(%rbp)
je 0x4a37
jmp 0x4a56
leaq 0x26916(%rip), %rdi     # 0x2b354
leaq 0x2683f(%rip), %rsi     # 0x2b284
movl $0x23c, %edx            # imm = 0x23C
leaq 0x2683c(%rip), %rcx     # 0x2b28d
callq 0x3220
movl -0x5e4(%rbp), %ecx
movq -0x590(%rbp), %rax
movl %ecx, 0x28(%rax)
movslq -0x5e4(%rbp), %rsi
leaq 0x3a96c(%rip), %rdi     # 0x3f3e0
callq 0xa1c0
movq %rax, %rdi
addq $0x30, %rdi
callq 0xa700
movq %rax, %rdx
movq -0x590(%rbp), %rax
movl 0x24(%rax), %ecx
addq %rdx, %rcx
movl %ecx, 0x24(%rax)
jmp 0x4aa8
movq -0x590(%rbp), %rax
movl $0xffffffff, 0x28(%rax) # imm = 0xFFFFFFFF
movl $0x3, -0x5e8(%rbp)
movq -0x590(%rbp), %rax
movzbl 0x21(%rax), %eax
andl $0x3, %eax
cmpl $0x3, %eax
jne 0x4c84
movq -0x590(%rbp), %rsi
leaq 0x3a921(%rip), %rdi     # 0x3f3f8
callq 0xa1e0
movq %rax, -0x7e8(%rbp)
jmp 0x4ae5
movq -0x7e8(%rbp), %rax
movq %rax, -0x5f0(%rbp)
leaq 0x3a8fe(%rip), %rdi     # 0x3f3f8
callq 0xa240
movq %rax, -0x5f8(%rbp)
leaq -0x5f0(%rbp), %rdi
leaq -0x5f8(%rbp), %rsi
callq 0xa210
testb $0x1, %al
jne 0x4b1f
jmp 0x4b8e
leaq 0x3a90a(%rip), %rdi     # 0x3f430
callq 0xa400
movl %eax, -0x5fc(%rbp)
movq -0x590(%rbp), %rsi
leaq 0x3a8b9(%rip), %rdi     # 0x3f3f8
leaq -0x5fc(%rbp), %rdx
callq 0xa720
movb %dl, -0x7f1(%rbp)
movq %rax, -0x7f0(%rbp)
jmp 0x4b5a
movb -0x7f1(%rbp), %al
movq -0x7f0(%rbp), %rcx
movq %rcx, -0x610(%rbp)
movb %al, -0x608(%rbp)
movq -0x590(%rbp), %rsi
leaq 0x3a8ae(%rip), %rdi     # 0x3f430
callq 0xa5f0
jmp 0x4b89
jmp 0x4c82
leaq -0x5f0(%rbp), %rdi
callq 0xa500
movslq 0x20(%rax), %rsi
leaq 0x3a88b(%rip), %rdi     # 0x3f430
callq 0x9fb0
movq %rax, -0x618(%rbp)
movq -0x618(%rbp), %rax
movzbl 0x20(%rax), %eax
cmpl $0x0, %eax
jne 0x4bf0
movq -0x590(%rbp), %rsi
movq -0x618(%rbp), %rdi
callq 0xa6c0
jmp 0x4bd6
movq -0x590(%rbp), %rsi
leaq 0x3a864(%rip), %rdi     # 0x3f448
callq 0xa770
jmp 0x4beb
jmp 0x4c80
movq -0x618(%rbp), %rax
movzbl 0x20(%rax), %eax
movq -0x590(%rbp), %rcx
movzbl 0x20(%rcx), %ecx
cmpl %ecx, %eax
jne 0x4c50
movq -0x618(%rbp), %rax
movzbl 0x21(%rax), %eax
movq -0x590(%rbp), %rcx
movzbl 0x21(%rcx), %ecx
cmpl %ecx, %eax
jne 0x4c50
movq -0x618(%rbp), %rax
movl 0x28(%rax), %eax
movq -0x590(%rbp), %rcx
cmpl 0x28(%rcx), %eax
jne 0x4c50
movq -0x618(%rbp), %rax
movl 0x24(%rax), %eax
movq -0x590(%rbp), %rcx
cmpl 0x24(%rcx), %eax
je 0x4c7e
movq -0x590(%rbp), %rdi
callq 0x3130
movq %rax, %rsi
leaq 0x26704(%rip), %rdi     # 0x2b36a
xorl %eax, %eax
callq 0x3360
jmp 0x4c6f
movl 0x3a723(%rip), %eax     # 0x3f398
addl $0x1, %eax
movl %eax, 0x3a71a(%rip)     # 0x3f398
jmp 0x4c80
jmp 0x4c82
jmp 0x4c84
jmp 0x4c86
leaq -0x580(%rbp), %rdi
callq 0xa7a0
jmp 0x473c
movl $0x1, -0x61c(%rbp)
movslq -0x61c(%rbp), %rsi
leaq 0x3a731(%rip), %rdi     # 0x3f3e0
callq 0xa1c0
addq $0x30, %rax
movq %rax, -0x628(%rbp)
movq -0x8(%rbp), %rdi
callq 0x9800
movq %rax, -0x630(%rbp)
leaq -0x630(%rbp), %rdi
callq 0x9900
movb %al, -0x7f2(%rbp)
jmp 0x4ce3
movb -0x7f2(%rbp), %al
movb %al, -0x631(%rbp)
movzbl -0x631(%rbp), %eax
cmpl $0x0, %eax
jne 0x4d26
movl $0x1, -0x638(%rbp)
leaq -0x458(%rbp), %rdi
callq 0x9c90
leaq -0x440(%rbp), %rdi
callq 0x9b30
addq $0x880, %rsp            # imm = 0x880
popq %rbp
retq
movzbl -0x631(%rbp), %eax
cmpl $0xf0, %eax
jge 0x4de1
movq -0x628(%rbp), %rdi
movq %rdi, -0x808(%rbp)
callq 0xa870
movq %rax, -0x648(%rbp)
leaq -0x640(%rbp), %rdi
leaq -0x648(%rbp), %rsi
callq 0xa8a0
movq -0x630(%rbp), %rax
movq %rax, -0x650(%rbp)
movzbl -0x631(%rbp), %eax
movl %eax, %esi
leaq -0x630(%rbp), %rdi
callq 0xa8e0
movq -0x808(%rbp), %rdi
movq %rax, -0x658(%rbp)
movq -0x640(%rbp), %rsi
movq -0x650(%rbp), %rdx
movq -0x658(%rbp), %rcx
callq 0xa7c0
movq %rax, -0x800(%rbp)
jmp 0x4db9
movq -0x800(%rbp), %rax
movq %rax, -0x660(%rbp)
movzbl -0x631(%rbp), %eax
movl %eax, %esi
leaq -0x630(%rbp), %rdi
callq 0xa920
jmp 0x4ccf
movzbl -0x631(%rbp), %eax
addl $0xffffff10, %eax       # imm = 0xFFFFFF10
movl %eax, %ecx
movq %rcx, -0x810(%rbp)
subl $0x6, %eax
ja 0x548f
movq -0x810(%rbp), %rax
leaq 0x261f7(%rip), %rcx     # 0x2b004
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
leaq -0x630(%rbp), %rdi
callq 0xa940
movw %ax, -0x812(%rbp)
jmp 0x4e2b
movw -0x812(%rbp), %ax
movw %ax, -0x662(%rbp)
movq -0x628(%rbp), %rdi
movq %rdi, -0x828(%rbp)
callq 0xa870
movq %rax, -0x678(%rbp)
leaq -0x670(%rbp), %rdi
leaq -0x678(%rbp), %rsi
callq 0xa8a0
movq -0x828(%rbp), %rdi
movzwl -0x662(%rbp), %eax
movl %eax, %edx
movb $0x0, -0x679(%rbp)
movq -0x670(%rbp), %rsi
leaq -0x679(%rbp), %rcx
callq 0xa9a0
movq %rax, -0x820(%rbp)
jmp 0x4e99
movq -0x820(%rbp), %rax
movq %rax, -0x688(%rbp)
jmp 0x548f
leaq -0x630(%rbp), %rdi
callq 0x9900
movb %al, -0x829(%rbp)
jmp 0x4ec0
movb -0x829(%rbp), %al
movb %al, -0x689(%rbp)
movzbl -0x689(%rbp), %eax
movl %eax, %esi
leaq -0x420(%rbp), %rdi
callq 0xa190
movl (%rax), %eax
movl %eax, -0x61c(%rbp)
xorl %eax, %eax
cmpl $0x0, -0x61c(%rbp)
movb %al, -0x82a(%rbp)
jle 0x4f2a
movslq -0x61c(%rbp), %rax
movq %rax, -0x838(%rbp)
leaq 0x3a4d1(%rip), %rdi     # 0x3f3e0
callq 0xa270
movq %rax, %rcx
movq -0x838(%rbp), %rax
cmpq %rcx, %rax
setb %al
movb %al, -0x82a(%rbp)
movb -0x82a(%rbp), %al
testb $0x1, %al
jne 0x4f36
jmp 0x4f38
jmp 0x4f57
leaq 0x2643e(%rip), %rdi     # 0x2b37d
leaq 0x2633e(%rip), %rsi     # 0x2b284
movl $0x27e, %edx            # imm = 0x27E
leaq 0x2633b(%rip), %rcx     # 0x2b28d
callq 0x3220
movslq -0x61c(%rbp), %rsi
leaq 0x3a47b(%rip), %rdi     # 0x3f3e0
callq 0xa1c0
addq $0x30, %rax
movq %rax, -0x628(%rbp)
jmp 0x548f
leaq 0x26435(%rip), %rdi     # 0x2b3b6
leaq 0x262fc(%rip), %rsi     # 0x2b284
movl $0x285, %edx            # imm = 0x285
leaq 0x262f9(%rip), %rcx     # 0x2b28d
callq 0x3220
leaq -0x6b8(%rbp), %rdi
callq 0xaa40
movb -0x631(%rbp), %al
subb $-0xc, %al
sete -0x6af(%rbp)
movl -0x61c(%rbp), %eax
movl %eax, -0x6b8(%rbp)
movq -0x628(%rbp), %rdi
callq 0xa700
movl %eax, -0x6b4(%rbp)
leaq -0x630(%rbp), %rdi
callq 0x9900
movb %al, -0x839(%rbp)
jmp 0x4fe6
movb -0x839(%rbp), %al
movb %al, -0x6b0(%rbp)
movq -0x628(%rbp), %rdi
movq %rdi, -0x850(%rbp)
callq 0xa870
movq %rax, -0x6c8(%rbp)
leaq -0x6c0(%rbp), %rdi
leaq -0x6c8(%rbp), %rsi
callq 0xa8a0
movq -0x850(%rbp), %rdi
movzbl -0x6b0(%rbp), %eax
movl %eax, %edx
movb $0x0, -0x6c9(%rbp)
movq -0x6c0(%rbp), %rsi
leaq -0x6c9(%rbp), %rcx
callq 0xa9a0
movq %rax, -0x848(%rbp)
jmp 0x5052
movq -0x848(%rbp), %rax
movq %rax, -0x6d8(%rbp)
movl $0x0, -0x6dc(%rbp)
leaq -0x630(%rbp), %rdi
callq 0x9900
movb %al, -0x851(%rbp)
jmp 0x507e
movb -0x851(%rbp), %al
movb %al, -0x631(%rbp)
movzbl -0x631(%rbp), %eax
cmpl $0x0, %eax
jne 0x50be
jmp 0x53f0
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x460(%rbp)
movl %eax, -0x464(%rbp)
leaq -0x6b8(%rbp), %rdi
callq 0xbdf0
jmp 0x5494
movzbl -0x631(%rbp), %eax
decl %eax
movl %eax, %ecx
movq %rcx, -0x860(%rbp)
subl $0x22, %eax
ja 0x53cc
movq -0x860(%rbp), %rax
leaq 0x25f39(%rip), %rcx     # 0x2b020
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movl -0x6dc(%rbp), %eax
incl %eax
movl %eax, -0x6dc(%rbp)
leaq -0x630(%rbp), %rdi
callq 0x9930
movl %eax, -0x864(%rbp)
jmp 0x5112
movl -0x864(%rbp), %eax
movl %eax, -0x6e0(%rbp)
leaq -0x6a8(%rbp), %rdi
leaq -0x631(%rbp), %rsi
leaq -0x6e0(%rbp), %rdx
callq 0xaa80
jmp 0x513a
jmp 0x53eb
movl -0x6dc(%rbp), %eax
incl %eax
movl %eax, -0x6dc(%rbp)
leaq -0x630(%rbp), %rdi
callq 0xa940
movw %ax, -0x866(%rbp)
jmp 0x5162
movw -0x866(%rbp), %ax
movw %ax, -0x6e2(%rbp)
movzwl -0x6e2(%rbp), %eax
movq %rax, -0x870(%rbp)
leaq -0x458(%rbp), %rdi
callq 0xa400
movq %rax, %rcx
movq -0x870(%rbp), %rax
cmpq %rcx, %rax
jae 0x519b
jmp 0x51ba
leaq 0x2622a(%rip), %rdi     # 0x2b3cc
leaq 0x260db(%rip), %rsi     # 0x2b284
movl $0x2a6, %edx            # imm = 0x2A6
leaq 0x260d8(%rip), %rcx     # 0x2b28d
callq 0x3220
movzwl -0x6e2(%rbp), %eax
movl %eax, %esi
leaq -0x458(%rbp), %rdi
callq 0x9fb0
movq %rax, -0x6f0(%rbp)
movq -0x6f0(%rbp), %rax
movzbl 0x20(%rax), %eax
andl $0xf, %eax
movl %eax, -0x874(%rbp)
je 0x520f
jmp 0x51ee
movl -0x874(%rbp), %eax
subl $0x1, %eax
je 0x5286
jmp 0x51ff
movl -0x874(%rbp), %eax
subl $0x2, %eax
je 0x5253
jmp 0x52b2
leaq -0x6a8(%rbp), %rdi
movl $0x1, -0x6f4(%rbp)
movl $0x0, -0x6f8(%rbp)
movq -0x6f0(%rbp), %rcx
addq $0x28, %rcx
leaq -0x6f4(%rbp), %rsi
leaq -0x6f8(%rbp), %rdx
callq 0x54c0
jmp 0x524a
movb $0x1, -0x6ae(%rbp)
jmp 0x52d1
leaq -0x6a8(%rbp), %rdi
movl $0x3, -0x6fc(%rbp)
movq -0x6f0(%rbp), %rcx
movq %rcx, %rdx
addq $0x24, %rdx
addq $0x28, %rcx
leaq -0x6fc(%rbp), %rsi
callq 0x5550
jmp 0x5284
jmp 0x52d1
leaq -0x6a8(%rbp), %rdi
movl $0x2, -0x700(%rbp)
movq -0x6f0(%rbp), %rdx
addq $0x24, %rdx
leaq -0x700(%rbp), %rsi
callq 0x55e0
jmp 0x52b0
jmp 0x52d1
leaq 0x26131(%rip), %rdi     # 0x2b3ea
leaq 0x25fc4(%rip), %rsi     # 0x2b284
movl $0x2b8, %edx            # imm = 0x2B8
leaq 0x25fc1(%rip), %rcx     # 0x2b28d
callq 0x3220
jmp 0x53eb
movl -0x6dc(%rbp), %eax
incl %eax
movl %eax, -0x6dc(%rbp)
leaq -0x630(%rbp), %rdi
callq 0x9900
movb %al, -0x875(%rbp)
jmp 0x52f8
movb -0x875(%rbp), %al
movb %al, -0x701(%rbp)
leaq -0x630(%rbp), %rdi
callq 0x9930
movl %eax, -0x87c(%rbp)
jmp 0x5318
movl -0x87c(%rbp), %eax
movl %eax, -0x708(%rbp)
movzbl -0x701(%rbp), %eax
movl %eax, %esi
leaq -0x420(%rbp), %rdi
callq 0xa190
movl (%rax), %eax
movl %eax, -0x70c(%rbp)
cmpl $0x0, -0x70c(%rbp)
jl 0x534c
jmp 0x536b
leaq 0x260b4(%rip), %rdi     # 0x2b407
leaq 0x25f2a(%rip), %rsi     # 0x2b284
movl $0x2c1, %edx            # imm = 0x2C1
leaq 0x25f27(%rip), %rcx     # 0x2b28d
callq 0x3220
leaq -0x6a8(%rbp), %rdi
leaq -0x631(%rbp), %rsi
leaq -0x708(%rbp), %rdx
leaq -0x70c(%rbp), %rcx
callq 0xab00
jmp 0x538e
jmp 0x53eb
leaq -0x6a8(%rbp), %rdi
leaq -0x631(%rbp), %rsi
callq 0xab90
jmp 0x53a5
jmp 0x53eb
movl -0x6dc(%rbp), %eax
decl %eax
movl %eax, -0x6dc(%rbp)
leaq -0x6a8(%rbp), %rdi
leaq -0x631(%rbp), %rsi
callq 0xab90
jmp 0x53ca
jmp 0x53eb
leaq 0x26046(%rip), %rdi     # 0x2b419
leaq 0x25eaa(%rip), %rsi     # 0x2b284
movl $0x2e1, %edx            # imm = 0x2E1
leaq 0x25ea7(%rip), %rcx     # 0x2b28d
callq 0x3220
jmp 0x506a
cmpl $0x1, -0x6dc(%rbp)
je 0x5415
leaq 0x2603b(%rip), %rdx     # 0x2b43b
movl $0x1, %edi
leaq -0x6b8(%rbp), %rsi
callq 0xac10
jmp 0x5413
jmp 0x5415
movslq -0x61c(%rbp), %rsi
leaq 0x39fbd(%rip), %rdi     # 0x3f3e0
callq 0xa1c0
movq %rax, %rdi
addq $0x48, %rdi
leaq -0x6b8(%rbp), %rsi
callq 0xbd70
jmp 0x543d
movl $0x8, -0x638(%rbp)
leaq -0x6b8(%rbp), %rdi
callq 0xbdf0
jmp 0x548f
jmp 0x548f
leaq -0x630(%rbp), %rdi
callq 0xa940
movw %ax, -0x87e(%rbp)
jmp 0x546c
movw -0x87e(%rbp), %ax
movw %ax, -0x70e(%rbp)
movzwl -0x70e(%rbp), %eax
movl %eax, %esi
leaq -0x630(%rbp), %rdi
callq 0xa920
jmp 0x4ccf
leaq -0x458(%rbp), %rdi
callq 0x9c90
leaq -0x440(%rbp), %rdi
callq 0x9b30
movq -0x460(%rbp), %rdi
callq 0x3540
nopl (%rax,%rax)