// File: /workspace/github_c_makefile_star2_O2/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 %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x28, %rsp
movq %rsi, %r15
movq %rdi, %r14
movq %rdi, 0x8(%rsp)
leaq 0x2138(%rip), %rsi      # 0x79b4
movq %r15, %rdi
callq 0x5464
testq %rax, %rax
je 0x5993
movq %rax, %rbx
movabsq $0x1017370696d, %rax    # imm = 0x1017370696D
movq %rax, 0x20(%rsp)
xorl %eax, %eax
xorl %ecx, %ecx
cmpq $0x4, %rax
je 0x58b7
cmpq $0x1, 0x58(%r14,%rax,8)
sbbb $-0x1, %cl
incq %rax
jmp 0x58a3
leaq 0x20(%rsp), %rdi
movb %cl, 0x6(%rdi)
pushq $0x1
popq %rsi
pushq $0x8
popq %rdx
movq %rbx, %rcx
callq 0x3160
cmpq $0x8, %rax
jne 0x59b2
leaq 0x14(%rsp), %rax
andl $0x0, (%rax)
pushq $0x8
popq %r13
xorl %ebp, %ebp
pushq $0x1
popq %r15
pushq $0xc
popq %r12
cmpq $0x4, %rbp
je 0x5956
movq 0x8(%rsp), %rax
movq 0x58(%rax,%rbp,8), %rax
testq %rax, %rax
je 0x5951
movb %bpl, 0x14(%rsp)
movl %r13d, 0x18(%rsp)
movl %eax, 0x1c(%rsp)
leaq 0x14(%rsp), %rdi
movq %r15, %rsi
movq %r12, %rdx
movq %rbx, %rcx
callq 0x3160
cmpq $0xc, %rax
jne 0x596c
movq 0x8(%rsp), %r14
movq 0x20(%r14,%rbp,8), %rdi
movq 0x58(%r14,%rbp,8), %rdx
movq %r15, %rsi
movq %rbx, %rcx
callq 0x3160
cmpq 0x58(%r14,%rbp,8), %rax
jne 0x5975
addl %eax, %r13d
addl $0xc, %r13d
incq %rbp
jmp 0x58ed
movq %rbx, %rdi
addq $0x28, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x3060
leaq 0x209f(%rip), %rdi      # 0x7a12
jmp 0x597c
leaq 0x20d2(%rip), %rdi      # 0x7a4e
callq 0x3130
leaq 0x8(%rsp), %rdi
callq 0x542e
pushq $0x1
popq %rdi
callq 0x3150
movq 0x565e(%rip), %rax      # 0xaff8
movq (%rax), %rdi
leaq 0x2014(%rip), %rsi      # 0x79b8
movq %r15, %rdx
xorl %eax, %eax
callq 0x30d0
xorl %edi, %edi
jmp 0x597c
leaq 0x2027(%rip), %rdi      # 0x79e0
jmp 0x597c