// File: /workspace/github_c_makefile_star2_O3/tstword[P]MIPSAssemblerC/src/mipsfhdr.c
// Function: write_object_file
void write_object_file(struct assembler *assembler, const char *file) {
    struct MIPS_file_header file_hdr;
    size_t nbytes;
    FILE *fp;

    if((fp = fopen_wrap(file, "wb+")) == NULL) {
        fprintf(stderr, "Failed to open output file '%s: Error: ", file);
        perror(NULL);
        destroy_assembler(&assembler);
        exit(EXIT_FAILURE);
    }

    memset((void *)&file_hdr, 0, sizeof(file_hdr));

    /* Magic number */
    memcpy((void *)file_hdr.m_magic, "mips", 4);

    /* Endianness check */
    uint16_t endian = 0x0201; /* If little endian result is 1, big endian result is 2 */
    file_hdr.m_endianness = *((uint8_t *)&endian);

    /* Version */
    file_hdr.m_version = 0x1;

    /* Section header count */
    file_hdr.m_shnum = 0;
    for(segment_t segment = 0; segment < MAX_SEGMENTS; ++segment) {
        if(assembler->segment_memory_offset[segment] > 0) {
            ++file_hdr.m_shnum;
        }
    }

    /* Write header to object file */
    nbytes = fwrite((void *)&file_hdr, 0x1, sizeof(file_hdr), fp);
    if(nbytes != sizeof(file_hdr)) {
        perror("Object Write Error: Failed to write file header: ");
        destroy_assembler(&assembler);
        exit(EXIT_FAILURE);
    }

    offset_t file_offset = sizeof(file_hdr);

    /* Write segment headers and their corresponding data */
    struct MIPS_sect_header section_hdr;

    /* Zero memory */
    memset((void *)&section_hdr, 0, sizeof(section_hdr));

    for(segment_t segment = 0; segment < MAX_SEGMENTS; ++segment) {
        if(assembler->segment_memory_offset[segment] > 0) {
            section_hdr.sh_segment = segment;
            section_hdr.sh_offset = file_offset;
            section_hdr.sh_size = assembler->segment_memory_offset[segment];

            nbytes = fwrite((void *)&section_hdr, 0x1, sizeof(section_hdr), fp);
            if(nbytes != sizeof(section_hdr)) {
                perror("Object Write Error: Failed to write section header header: ");
                destroy_assembler(&assembler);
                exit(EXIT_FAILURE);
            }

            nbytes = fwrite(assembler->segment_memory[segment], 0x1, assembler->segment_memory_offset[segment], fp);
            if(nbytes != assembler->segment_memory_offset[segment]) {
                perror("Object Write Error: Failed to write memory to file: ");
                destroy_assembler(&assembler);
                exit(EXIT_FAILURE);
            }

            file_offset += sizeof(section_hdr) + assembler->segment_memory_offset[segment];
        }
    }

    fclose(fp);
}

// Assembly:
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x20, %rsp
movq %rsi, %r15
movq %rdi, %r14
movq %rdi, (%rsp)
leaq 0x1c9e(%rip), %rsi      # 0x79b4
movq %r15, %rdi
callq 0x5948
testq %rax, %rax
je 0x5e59
movq %rax, %rbx
movabsq $0x1017370696d, %rax    # imm = 0x1017370696D
movq %rax, 0x18(%rsp)
pxor %xmm0, %xmm0
xorl %eax, %eax
pcmpeqd %xmm2, %xmm2
pxor %xmm1, %xmm1
movdqu 0x58(%r14,%rax,8), %xmm3
pcmpeqd %xmm0, %xmm3
pshufd $0xb1, %xmm3, %xmm4     # xmm4 = xmm3[1,0,3,2]
pand %xmm3, %xmm4
packssdw %xmm4, %xmm4
pxor %xmm2, %xmm4
packssdw %xmm4, %xmm4
packsswb %xmm4, %xmm4
psubb %xmm4, %xmm1
addq $0x2, %rax
cmpq $0x4, %rax
jne 0x5d47
movdqa %xmm1, %xmm0
psrlw $0x8, %xmm0
paddb %xmm1, %xmm0
movd %xmm0, %eax
leaq 0x18(%rsp), %rdi
movb %al, 0x6(%rdi)
movl $0x1, %esi
movl $0x8, %edx
movq %rbx, %rcx
callq 0x3160
cmpq $0x8, %rax
jne 0x5e64
leaq 0x8(%rsp), %r14
movl $0x0, 0x8(%r14)
movq $0x0, (%r14)
movl $0x8, %r15d
movq (%rsp), %r13
xorl %r12d, %r12d
movq 0x58(%r13,%r12,8), %rax
testq %rax, %rax
je 0x5e2b
movb %r12b, 0x8(%rsp)
movl %r15d, 0xc(%rsp)
movl %eax, 0x10(%rsp)
movl $0x1, %esi
movl $0xc, %edx
movq %r14, %rdi
movq %rbx, %rcx
callq 0x3160
cmpq $0xc, %rax
jne 0x5e51
movq (%rsp), %r13
movq 0x20(%r13,%r12,8), %rdi
movq 0x58(%r13,%r12,8), %rdx
movl $0x1, %esi
movq %rbx, %rcx
callq 0x3160
cmpq 0x58(%r13,%r12,8), %rax
jne 0x5e49
addl %eax, %r15d
addl $0xc, %r15d
incq %r12
cmpq $0x4, %r12
jne 0x5dcf
movq %rbx, %rdi
addq $0x20, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
jmp 0x3060
movq %rsp, %rdi
callq 0x3490
movq %rsp, %rdi
callq 0x3470
movq %rsp, %rsi
movq %r15, %rdi
callq 0x34b0
movq %rsp, %rdi
callq 0x3450