// File: /workspace/github_cpp_makefile_star2_O2/ksherlock[P]wdc-utils/omf.cpp
// Function: add_relocs(std::vector<unsigned char, std::allocator<unsigned char>>&, unsigned long, omf::segment&, bool, bool)
uint32_t add_relocs(std::vector<uint8_t> &data, size_t data_offset, omf::segment &seg, bool compress, bool super) {

	std::array< optional<super_helper>, 38 > ss;


	uint32_t reloc_size = 0;

	for (auto &r : seg.relocs) {

		if (compress && r.can_compress()) {

			if (super) {
				if (r.shift == 0 && r.size == 2) {
					constexpr int n = SUPER_RELOC2;

					auto &sr = ss[n];
					if (!sr) sr.emplace();
					sr->append(r.offset);

					uint32_t value = r.value;
					for (int i = 0; i < 2; ++i, value >>= 8)
						data[data_offset + r.offset + i] = value; 
					continue;
				}

				// sreloc 3 is for 3 bytes.  however 4 bytes is also ok since 
				// it's 24-bit address space.
				if (r.shift == 0 && (r.size == 2 || r.size == 3))
				{
					constexpr int n = SUPER_RELOC3;

					auto &sr = ss[n];
					if (!sr) sr.emplace();
					sr->append(r.offset);

					uint32_t value = r.value;
					for (int i = 0; i < 3; ++i, value >>= 8)
						data[data_offset + r.offset + i] = value; 
					continue;	
				}

				// if size == 2 && shift == -16, -> SUPER INTERSEG 
				if (seg.segnum <= 12 && r.shift == 0xf0 && r.size == 2) {

					int n = SUPER_INTERSEG24 + seg.segnum;
					auto &sr = ss[n];
					if (!sr) sr.emplace();
					sr->append(r.offset);

					uint32_t value = r.value;
					for (int i = 0; i < 2; ++i, value >>= 8)
						data[data_offset + r.offset + i] = value; 
					continue;
				}
			}

			push(data, (uint8_t)omf::cRELOC);
			push(data, (uint8_t)r.size);
			push(data, (uint8_t)r.shift);
			push(data, (uint16_t)r.offset);
			push(data, (uint16_t)r.value);
			reloc_size += 7;
		} else {
			push(data, (uint8_t)omf::RELOC);
			push(data, (uint8_t)r.size);
			push(data, (uint8_t)r.shift);
			push(data, (uint32_t)r.offset);
			push(data, (uint32_t)r.value);
			reloc_size += 11;
		}
	}

	for (const auto &r : seg.intersegs) {
		if (compress && r.can_compress()) {

			if (super) {

				if (r.shift == 0 && r.size == 3) {
					constexpr int n = SUPER_INTERSEG1;
					auto &sr = ss[n];
					if (!sr) sr.emplace();
					sr->append(r.offset);

					uint32_t value = r.segment_offset;

					data[data_offset + r.offset + 0] = value; value >>= 8;
					data[data_offset + r.offset + 1] = value; value >>= 8;
					data[data_offset + r.offset + 2] = r.segment;
					continue;
				}


				if (r.shift == 0 && r.size == 2 && r.segment <= 12) {

					int n = SUPER_INTERSEG12 + r.segment;
					auto &sr = ss[n];
					if (!sr) sr.emplace();
					sr->append(r.offset);

					uint32_t value = r.segment_offset;
					for (int i = 0; i < 2; ++i, value >>= 8)
						data[data_offset + r.offset + i] = value; 
					continue;
				}

				if (r.shift == 0xf0 && r.size == 2 && r.segment <= 12) {

					int n = SUPER_INTERSEG24 + r.segment;
					auto &sr = ss[n];
					if (!sr) sr.emplace();
					sr->append(r.offset);

					uint32_t value = r.segment_offset;
					for (int i = 0; i < 2; ++i, value >>= 8)
						data[data_offset + r.offset + i] = value; 
					continue;
				}
			}


			push(data, (uint8_t)omf::cINTERSEG);
			push(data, (uint8_t)r.size);
			push(data, (uint8_t)r.shift);
			push(data, (uint16_t)r.offset);
			push(data, (uint8_t)r.segment);
			push(data, (uint16_t)r.segment_offset);
			reloc_size += 8;
		} else {
			push(data, (uint8_t)omf::INTERSEG);
			push(data, (uint8_t)r.size);
			push(data, (uint8_t)r.shift);
			push(data, (uint32_t)r.offset);
			push(data, (uint16_t)r.file);
			push(data, (uint16_t)r.segment);
			push(data, (uint32_t)r.segment_offset);
			reloc_size += 15;
		}
	}


	for (int i = 0; i < ss.size(); ++i) {
		auto &s = ss[i];
		if (!s) continue;

		auto tmp = s->data();
		if (tmp.empty()) continue;

		reloc_size += tmp.size() + 6;
		data.push_back(omf::SUPER);
		push(data, ((uint32_t)tmp.size() + 1));
		data.push_back(i);

		data.insert(data.end(), tmp.begin(), tmp.end());
	}

	return reloc_size;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x628, %rsp            # imm = 0x628
movl %r8d, 0x10(%rsp)
movl %ecx, 0x14(%rsp)
movq %rdx, %r14
movq %rsi, %rbp
movq %rdi, %rbx
leaq 0x38(%rsp), %rdi
callq 0xbcba
movq 0x80(%r14), %r13
movq %r14, 0x18(%rsp)
movq 0x88(%r14), %r12
movq $0x0, 0x8(%rsp)
leaq 0x40(%rsp), %r15
cmpq %r12, %r13
je 0xb0ac
cmpb $0x0, 0x14(%rsp)
je 0xaf4a
movl 0x4(%r13), %esi
cmpl $0xffff, %esi           # imm = 0xFFFF
ja 0xaf4a
cmpl $0xffff, 0x8(%r13)      # imm = 0xFFFF
ja 0xaf4a
cmpb $0x0, 0x10(%rsp)
je 0xb05e
movb (%r13), %dl
movb 0x1(%r13), %al
movl %edx, %ecx
xorb $0x2, %cl
movl %eax, %edi
orb %cl, %dil
jne 0xaf9f
cmpb $0x0, 0x38(%rsp)
jne 0xaf21
leaq 0x38(%rsp), %rdi
callq 0xbe9e
movl 0x4(%r13), %esi
movq %r15, %rdi
callq 0xbeb8
movl 0x8(%r13), %eax
xorl %ecx, %ecx
cmpq $0x2, %rcx
je 0xaf96
movl 0x4(%r13), %edx
addq (%rbx), %rdx
addq %rbp, %rdx
movb %al, (%rcx,%rdx)
incq %rcx
shrl $0x8, %eax
jmp 0xaf2f
movq %rbx, %rdi
movl $0xe2, %esi
callq 0xad34
movzbl (%r13), %esi
movq %rbx, %rdi
callq 0xad34
movzbl 0x1(%r13), %esi
movq %rbx, %rdi
callq 0xad34
movl 0x4(%r13), %esi
movq %rbx, %rdi
callq 0xad75
movl 0x8(%r13), %esi
movq %rbx, %rdi
callq 0xad75
movq 0x8(%rsp), %rax
addl $0xb, %eax
movq %rax, 0x8(%rsp)
addq $0xc, %r13
jmp 0xaec3
andb $-0x2, %dl
xorb $0x2, %dl
orb %al, %dl
jne 0xafe9
cmpb $0x0, 0x60(%rsp)
jne 0xafbe
leaq 0x60(%rsp), %rdi
callq 0xbe9e
movl 0x4(%r13), %esi
leaq 0x68(%rsp), %rdi
callq 0xbeb8
movl 0x8(%r13), %eax
xorl %ecx, %ecx
cmpq $0x3, %rcx
je 0xaf96
movl 0x4(%r13), %edx
addq (%rbx), %rdx
addq %rbp, %rdx
movb %al, (%rcx,%rdx)
incq %rcx
shrl $0x8, %eax
jmp 0xafce
movq 0x18(%rsp), %rdx
movzwl (%rdx), %edx
cmpq $0xd, %rdx
setb %dil
xorb $-0x10, %al
orb %cl, %al
sete %al
andb %dil, %al
cmpb $0x1, %al
jne 0xb05e
imulq $0x28, %rdx, %rax
leaq 0x38(%rsp), %rcx
leaq (%rax,%rcx), %r14
addq $0x3e8, %r14            # imm = 0x3E8
cmpb $0x0, (%r14)
jne 0xb02d
movq %r14, %rdi
callq 0xbe9e
movl 0x4(%r13), %esi
addq $0x8, %r14
movq %r14, %rdi
callq 0xbeb8
movl 0x8(%r13), %eax
xorl %ecx, %ecx
cmpq $0x2, %rcx
je 0xaf96
movl 0x4(%r13), %edx
addq (%rbx), %rdx
addq %rbp, %rdx
movb %al, (%rcx,%rdx)
incq %rcx
shrl $0x8, %eax
jmp 0xb03f
movq %rbx, %rdi
movl $0xf5, %esi
callq 0xad34
movzbl (%r13), %esi
movq %rbx, %rdi
callq 0xad34
movzbl 0x1(%r13), %esi
movq %rbx, %rdi
callq 0xad34
movzwl 0x4(%r13), %esi
movq %rbx, %rdi
callq 0xad47
movzwl 0x8(%r13), %esi
movq %rbx, %rdi
callq 0xad47
movq 0x8(%rsp), %rax
addl $0x7, %eax
jmp 0xaf91
movq 0x18(%rsp), %rax
movq 0x68(%rax), %r13
movq 0x70(%rax), %r12
cmpq %r12, %r13
je 0xb2e5
cmpb $0x0, 0x14(%rsp)
je 0xb148
movq %r13, %rdi
callq 0xbfae
testb %al, %al
je 0xb148
cmpb $0x0, 0x10(%rsp)
je 0xb28a
movb (%r13), %al
movb 0x1(%r13), %cl
movl %eax, %edx
xorb $0x3, %dl
orb %cl, %dl
jne 0xb1b7
cmpb $0x0, 0x88(%rsp)
jne 0xb10c
leaq 0x88(%rsp), %rdi
callq 0xbe9e
movl 0x4(%r13), %esi
leaq 0x90(%rsp), %rdi
callq 0xbeb8
movl 0x4(%r13), %ecx
movl 0xc(%r13), %eax
addq (%rbx), %rcx
movb %al, (%rbp,%rcx)
movl 0x4(%r13), %ecx
addq (%rbx), %rcx
movb %ah, 0x1(%rbp,%rcx)
movb 0xa(%r13), %al
movl 0x4(%r13), %ecx
addq (%rbx), %rcx
movb %al, 0x2(%rbp,%rcx)
jmp 0xb1ae
movq %rbx, %rdi
movl $0xe3, %esi
callq 0xad34
movzbl (%r13), %esi
movq %rbx, %rdi
callq 0xad34
movzbl 0x1(%r13), %esi
movq %rbx, %rdi
callq 0xad34
movl 0x4(%r13), %esi
movq %rbx, %rdi
callq 0xad75
movzwl 0x8(%r13), %esi
movq %rbx, %rdi
callq 0xad47
movzwl 0xa(%r13), %esi
movq %rbx, %rdi
callq 0xad47
movl 0xc(%r13), %esi
movq %rbx, %rdi
callq 0xad75
movq 0x8(%rsp), %rax
addl $0xf, %eax
movq %rax, 0x8(%rsp)
addq $0x10, %r13
jmp 0xb0b9
xorb $0x2, %al
movl %ecx, %edx
orb %al, %dl
jne 0xb221
movzwl 0xa(%r13), %eax
cmpq $0xc, %rax
ja 0xb28a
imulq $0x28, %rax, %rax
leaq 0x38(%rsp), %rcx
leaq (%rax,%rcx), %r14
addq $0x208, %r14            # imm = 0x208
cmpb $0x0, (%r14)
jne 0xb1f0
movq %r14, %rdi
callq 0xbe9e
addq $0x8, %r14
movl 0x4(%r13), %esi
movq %r14, %rdi
callq 0xbeb8
movl 0xc(%r13), %eax
xorl %ecx, %ecx
cmpq $0x2, %rcx
je 0xb1ae
movl 0x4(%r13), %edx
addq (%rbx), %rdx
addq %rbp, %rdx
movb %al, (%rcx,%rdx)
incq %rcx
shrl $0x8, %eax
jmp 0xb206
xorb $-0x10, %cl
orb %al, %cl
jne 0xb28a
movzwl 0xa(%r13), %eax
cmpq $0xc, %rax
ja 0xb28a
imulq $0x28, %rax, %rax
leaq 0x38(%rsp), %rcx
leaq (%rax,%rcx), %r14
addq $0x3e8, %r14            # imm = 0x3E8
cmpb $0x0, (%r14)
jne 0xb255
movq %r14, %rdi
callq 0xbe9e
addq $0x8, %r14
movl 0x4(%r13), %esi
movq %r14, %rdi
callq 0xbeb8
movl 0xc(%r13), %eax
xorl %ecx, %ecx
cmpq $0x2, %rcx
je 0xb1ae
movl 0x4(%r13), %edx
addq (%rbx), %rdx
addq %rbp, %rdx
movb %al, (%rcx,%rdx)
incq %rcx
shrl $0x8, %eax
jmp 0xb26b
movq %rbx, %rdi
movl $0xf6, %esi
callq 0xad34
movzbl (%r13), %esi
movq %rbx, %rdi
callq 0xad34
movzbl 0x1(%r13), %esi
movq %rbx, %rdi
callq 0xad34
movzwl 0x4(%r13), %esi
movq %rbx, %rdi
callq 0xad47
movzbl 0xa(%r13), %esi
movq %rbx, %rdi
callq 0xad34
movzwl 0xc(%r13), %esi
movq %rbx, %rdi
callq 0xad47
movq 0x8(%rsp), %rax
addl $0x8, %eax
jmp 0xb1a9
xorl %ebp, %ebp
leaq 0x20(%rsp), %r12
movq %r15, %rsi
cmpq $0x26, %rbp
je 0xb399
cmpb $0x1, -0x8(%rsi)
jne 0xb38d
movq %r12, %r15
movq %r12, %rdi
movq %rsi, %r14
callq 0x7700
movq 0x20(%rsp), %r12
movq 0x28(%rsp), %r13
cmpq %r13, %r12
je 0xb37f
movb $-0x9, 0x7(%rsp)
movq %rbx, %rdi
leaq 0x7(%rsp), %rsi
callq 0xc122
movl 0x28(%rsp), %esi
subl 0x20(%rsp), %esi
incl %esi
movq %rbx, %rdi
callq 0xad75
movb %bpl, 0x7(%rsp)
movq %rbx, %rdi
leaq 0x7(%rsp), %rsi
callq 0xc122
movq 0x8(%rbx), %rsi
movq 0x20(%rsp), %rdx
movq 0x28(%rsp), %rcx
movq %rbx, %rdi
callq 0xbfd4
subl %r12d, %r13d
movq 0x8(%rsp), %rax
addl %r13d, %eax
addl $0x6, %eax
movq %rax, 0x8(%rsp)
movq %r15, %r12
movq %r15, %rdi
callq 0x6ac0
movq %r14, %rsi
incq %rbp
addq $0x28, %rsi
jmp 0xb2ef
leaq 0x38(%rsp), %rdi
callq 0xbff4
movq 0x8(%rsp), %rax
addq $0x628, %rsp            # imm = 0x628
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0xb3df
jmp 0xb3df
jmp 0xb3df
jmp 0xb3df
jmp 0xb3df
jmp 0xb3df
jmp 0xb3cc
jmp 0xb3cc
jmp 0xb3cc
movq %rax, %rbx
leaq 0x20(%rsp), %rdi
callq 0x6ac0
jmp 0xb3e2
jmp 0xb3df
jmp 0xb3df
movq %rax, %rbx
leaq 0x38(%rsp), %rdi
callq 0xbff4
movq %rbx, %rdi
callq 0x23c0