📄 coff-objfmt.c
字号:
if (rel) { if (objfmt_coff->machine == COFF_MACHINE_I386) reloc->type = COFF_RELOC_I386_REL32; else if (objfmt_coff->machine == COFF_MACHINE_AMD64) reloc->type = COFF_RELOC_AMD64_REL32; else yasm_internal_error(N_("coff objfmt: unrecognized machine")); /* For standard COFF, need to reference to start of section, so add * $$ in. * For Win32 COFF, need to reference to next bytecode, so add '$' * (really $+$.len) in. */ if (objfmt_coff->win32) *ep = yasm_expr_create(YASM_EXPR_ADD, yasm_expr_expr(*ep), yasm_expr_sym(yasm_symtab_define_label2("$", bc, 0, (*ep)->line)), (*ep)->line); else *ep = yasm_expr_create(YASM_EXPR_ADD, yasm_expr_expr(*ep), yasm_expr_sym(yasm_symtab_define_label2("$$", yasm_section_bcs_first(info->sect), 0, (*ep)->line)), (*ep)->line); *ep = yasm_expr_simplify(*ep, yasm_common_calc_bc_dist); } else { if (objfmt_coff->machine == COFF_MACHINE_I386) reloc->type = COFF_RELOC_I386_ADDR32; else if (objfmt_coff->machine == COFF_MACHINE_AMD64) reloc->type = COFF_RELOC_AMD64_ADDR32; else yasm_internal_error(N_("coff objfmt: unrecognized machine")); } info->csd->nreloc++; yasm_section_add_reloc(info->sect, (yasm_reloc *)reloc, yasm_xfree); } intn = yasm_expr_get_intnum(ep, NULL); if (intn) { if (rel) { int retval = yasm_arch_intnum_fixup_rel(objfmt_coff->arch, intn, valsize, bc, bc->line); if (retval) return retval; } return yasm_arch_intnum_tobytes(objfmt_coff->arch, intn, buf, destsize, valsize, shift, bc, warn, bc->line); } /* Check for complex float expressions */ if (yasm_expr__contains(*ep, YASM_EXPR_FLOAT)) { yasm__error(bc->line, N_("floating point expression too complex")); return 1; } yasm__error(bc->line, N_("coff: relocation too complex")); return 1;}static intcoff_objfmt_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d){ /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d; /*@null@*/ /*@only@*/ unsigned char *bigbuf; unsigned long size = REGULAR_OUTBUF_SIZE; unsigned long multiple; unsigned long i; int gap; assert(info != NULL); bigbuf = yasm_bc_tobytes(bc, info->buf, &size, &multiple, &gap, info, coff_objfmt_output_expr, NULL); /* Don't bother doing anything else if size ended up being 0. */ if (size == 0) { if (bigbuf) yasm_xfree(bigbuf); return 0; } info->csd->size += multiple*size; /* Warn that gaps are converted to 0 and write out the 0's. */ if (gap) { unsigned long left; yasm__warning(YASM_WARN_GENERAL, bc->line, N_("uninitialized space declared in code/data section: zeroing")); /* Write out in chunks */ memset(info->buf, 0, REGULAR_OUTBUF_SIZE); left = multiple*size; while (left > REGULAR_OUTBUF_SIZE) { fwrite(info->buf, REGULAR_OUTBUF_SIZE, 1, info->f); left -= REGULAR_OUTBUF_SIZE; } fwrite(info->buf, left, 1, info->f); } else { /* Output multiple copies of buf (or bigbuf if non-NULL) to file */ for (i=0; i<multiple; i++) fwrite(bigbuf ? bigbuf : info->buf, (size_t)size, 1, info->f); } /* If bigbuf was allocated, free it */ if (bigbuf) yasm_xfree(bigbuf); return 0;}static intcoff_objfmt_output_section(yasm_section *sect, /*@null@*/ void *d){ /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d; /*@dependent@*/ /*@null@*/ coff_section_data *csd; long pos; coff_reloc *reloc; /* Don't output absolute sections into the section table */ if (yasm_section_is_absolute(sect)) return 0; assert(info != NULL); csd = yasm_section_get_data(sect, &coff_section_data_cb); assert(csd != NULL); csd->addr = info->addr; if ((csd->flags & COFF_STYP_STD_MASK) == COFF_STYP_BSS) { yasm_bytecode *last = yasm_section_bcs_last(sect); /* Don't output BSS sections. * TODO: Check for non-reserve bytecodes? */ pos = 0; /* position = 0 because it's not in the file */ csd->size = last->offset + last->len; } else { yasm_bytecode *last = yasm_section_bcs_last(sect); pos = ftell(info->f); if (pos == -1) { yasm__fatal(N_("could not get file position on output file")); /*@notreached@*/ return 1; } info->sect = sect; info->csd = csd; yasm_section_bcs_traverse(sect, info, coff_objfmt_output_bytecode); /* Sanity check final section size */ if (csd->size != (last->offset + last->len)) yasm_internal_error( N_("coff: section computed size did not match actual size")); } /* Empty? Go on to next section */ if (csd->size == 0) return 0; info->addr += csd->size; csd->scnptr = (unsigned long)pos; /* No relocations to output? Go on to next section */ if (csd->nreloc == 0) return 0; pos = ftell(info->f); if (pos == -1) { yasm__fatal(N_("could not get file position on output file")); /*@notreached@*/ return 1; } csd->relptr = (unsigned long)pos; reloc = (coff_reloc *)yasm_section_relocs_first(sect); while (reloc) { unsigned char *localbuf = info->buf; /*@null@*/ coff_symrec_data *csymd; csymd = yasm_symrec_get_data(reloc->reloc.sym, &coff_symrec_data_cb); if (!csymd) yasm_internal_error( N_("coff: no symbol data for relocated symbol")); yasm_intnum_get_sized(reloc->reloc.addr, localbuf, 4, 32, 0, 0, 0, 0); localbuf += 4; /* address of relocation */ YASM_WRITE_32_L(localbuf, csymd->index); /* relocated symbol */ YASM_WRITE_16_L(localbuf, reloc->type); /* type of relocation */ fwrite(info->buf, 10, 1, info->f); reloc = (coff_reloc *)yasm_section_reloc_next((yasm_reloc *)reloc); } return 0;}static intcoff_objfmt_output_secthead(yasm_section *sect, /*@null@*/ void *d){ /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d; yasm_objfmt_coff *objfmt_coff; /*@dependent@*/ /*@null@*/ coff_section_data *csd; unsigned char *localbuf; /* Don't output absolute sections into the section table */ if (yasm_section_is_absolute(sect)) return 0; assert(info != NULL); objfmt_coff = info->objfmt_coff; csd = yasm_section_get_data(sect, &coff_section_data_cb); assert(csd != NULL); localbuf = info->buf; strncpy((char *)localbuf, yasm_section_get_name(sect), 8);/* section name */ localbuf += 8; YASM_WRITE_32_L(localbuf, csd->addr); /* physical address */ if (COFF_SET_VMA) YASM_WRITE_32_L(localbuf, csd->addr); /* virtual address */ else YASM_WRITE_32_L(localbuf, 0); /* virtual address */ YASM_WRITE_32_L(localbuf, csd->size); /* section size */ YASM_WRITE_32_L(localbuf, csd->scnptr); /* file ptr to data */ YASM_WRITE_32_L(localbuf, csd->relptr); /* file ptr to relocs */ YASM_WRITE_32_L(localbuf, 0); /* file ptr to line nums */ if (csd->nreloc >= 64*1024) { yasm__warning(YASM_WARN_GENERAL, 0, N_("too many relocations in section `%s'"), yasm_section_get_name(sect)); YASM_WRITE_16_L(localbuf, 0xFFFF); /* max out */ } else YASM_WRITE_16_L(localbuf, csd->nreloc); /* num of relocation entries */ YASM_WRITE_16_L(localbuf, 0); /* num of line number entries */ YASM_WRITE_32_L(localbuf, csd->flags); /* flags */ fwrite(info->buf, 40, 1, info->f); return 0;}static voidcoff_objfmt_output(yasm_objfmt *objfmt, FILE *f, const char *obj_filename, int all_syms, /*@unused@*/ yasm_dbgfmt *df){ yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)objfmt; coff_objfmt_output_info info; unsigned char *localbuf; long pos; unsigned long symtab_pos; unsigned long symtab_count = 0; unsigned long strtab_offset = 4; coff_symtab_entry *entry; info.objfmt_coff = objfmt_coff; info.f = f; info.buf = yasm_xmalloc(REGULAR_OUTBUF_SIZE); /* Allocate space for headers by seeking forward */ if (fseek(f, (long)(20+40*(objfmt_coff->parse_scnum-1)), SEEK_SET) < 0) { yasm__fatal(N_("could not seek on output file")); /*@notreached@*/ return; } /* Section data/relocs */ if (COFF_SET_VMA) { /* If we're setting the VMA, we need to do a first section pass to * determine each section's addr value before actually outputting * relocations, as a relocation's section address is added into the * addends in the generated code. */ info.addr = 0; if (yasm_object_sections_traverse(objfmt_coff->object, &info, coff_objfmt_set_section_addr)) return; } info.addr = 0; if (yasm_object_sections_traverse(objfmt_coff->object, &info, coff_objfmt_output_section)) return; /* Symbol table */ if (all_syms) { /* Need to put all local syms into COFF symbol table */ yasm_symtab_traverse(objfmt_coff->symtab, objfmt_coff, coff_objfmt_append_local_sym); } pos = ftell(f); if (pos == -1) { yasm__fatal(N_("could not get file position on output file")); /*@notreached@*/ return; } symtab_pos = (unsigned long)pos; STAILQ_FOREACH(entry, &objfmt_coff->coff_symtab, link) { const char *name = yasm_symrec_get_name(entry->sym); const yasm_expr *equ_val; const yasm_intnum *intn; size_t len = strlen(name); int aux; /*@dependent@*/ /*@null@*/ coff_symrec_data *csymd; unsigned long value = 0; unsigned int scnum = 0xfffe; /* -2 = debugging symbol */ /*@dependent@*/ /*@null@*/ yasm_section *sect; /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc; unsigned long scnlen = 0; /* for sect auxent */ unsigned long nreloc = 0; /* for sect auxent */ /* Get symrec's of_data (needed for storage class) */ csymd = yasm_symrec_get_data(entry->sym, &coff_symrec_data_cb); if (!csymd) yasm_internal_error(N_("coff: expected sym data to be present")); /* Look at symrec for value/scnum/etc. */ if (yasm_symrec_get_label(entry->sym, &precbc)) { if (precbc) sect = yasm_bc_get_section(precbc); else sect = NULL; /* it's a label: get value and offset. * If there is not a section, leave as debugging symbol. */ if (sect) { /*@dependent@*/ /*@null@*/ coff_section_data *csectd; csectd = yasm_section_get_data(sect, &coff_section_data_cb); if (csectd) { scnum = csectd->scnum; scnlen = csectd->size; nreloc = csectd->nreloc; if (COFF_SET_VMA) value = csectd->addr; } else if (yasm_section_is_absolute(sect)) { yasm_expr *abs_start; abs_start = yasm_expr_copy(yasm_section_get_start(sect)); intn = yasm_expr_get_intnum(&abs_start, yasm_common_calc_bc_dist); if (!intn) yasm__error(abs_start->line, N_("absolute section start not an integer expression")); else value = yasm_intnum_get_uint(intn); yasm_expr_destroy(abs_start); scnum = 0xffff; /* -1 = absolute symbol */ } else yasm_internal_error(N_("didn't understand section")); if (precbc) value += precbc->offset + precbc->len; } } else if ((equ_val = yasm_symrec_get_equ(entry->sym))) { yasm_expr *equ_val_copy = yasm_expr_copy(equ_val); intn = yasm_expr_get_intnum(&equ_val_copy, yasm_common_calc_bc_dist); if (!intn) { yasm_sym_vis vis = yasm_symrec_get_visibility(entry->sym); if (vis & YASM_SYM_GLOBAL) yasm__error(equ_val->line, N_("global EQU value not an integer expression")); } else value = yasm_intnum_get_uint(intn); yasm_expr_destroy(equ_val_copy); scnum = 0xffff; /* -1 = absolute symbol */ } else { yasm_sym_vis vis = yasm_symrec_get_visibility(entry->sym); if (vis & YASM_SYM_COMMON) { intn = yasm_expr_get_intnum(&csymd->size, yasm_common_calc_bc_dist); if (!intn) yasm__error(csymd->size->line, N_("COMMON data size not an integer expression")); else value = yasm_intnum_get_uint(intn); scnum = 0; } if (vis & YASM_SYM_EXTERN) scnum = 0; } localbuf = info.buf; if (len > 8) { YASM_WRITE_32_L(localbuf, 0); /* "zeros" field */ YASM_WRITE_32_L(localbuf, strtab_offset); /* string table offset */ strtab_offset += len+1; } else { /* <8 chars, so no string table entry needed */ strncpy((char *)localbuf, name, 8); localbuf += 8; } YASM_WRITE_32_L(localbuf, value); /* value */ YASM_WRITE_16_L(localbuf, scnum); /* section number */ YASM_WRITE_16_L(localbuf, 0); /* type is always zero (for now) */ YASM_WRITE_8(localbuf, csymd->sclass); /* storage class */ YASM_WRITE_8(localbuf, entry->numaux); /* number of aux entries */ fwrite(info.buf, 18, 1, f); for (aux=0; aux<entry->numaux; aux++) { localbuf = info.buf; memset(localbuf, 0, 18); switch (entry->auxtype) { case COFF_SYMTAB_AUX_NONE: break; case COFF_SYMTAB_AUX_SECT: YASM_WRITE_32_L(localbuf, scnlen); /* section length */ YASM_WRITE_16_L(localbuf, nreloc); /* number relocs */ YASM_WRITE_16_L(localbuf, 0); /* number line nums */ break; case COFF_SYMTAB_AUX_FILE: len = strlen(entry->aux[0].fname); if (len > 14) { YASM_WRITE_32_L(localbuf, 0); YASM_WRITE_32_L(localbuf, strtab_offset); strtab_offset += len+1; } else strncpy((char *)localbuf, entry->aux[0].fname, 14); break; default: yasm_internal_error( N_("coff: unrecognized aux symtab type")); } fwrite(info.buf, 18, 1, f); symtab_count++; } symtab_count++; } /* String table */ yasm_fwrite_32_l(strtab_offset, f); /* first four bytes are total length */ STAILQ_FOREACH(entry, &objfmt_coff->coff_symtab, link) { const char *name = yasm_symrec_get_name(entry->sym); size_t len = strlen(name); int aux; if (len > 8) fwrite(name, len+1, 1, f);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -