📄 outobj.c
字号:
/* * handle absolute-assembly (structure definitions) */ if (segto == NO_SEG) { if ((type & OUT_TYPMASK) != OUT_RESERVE) error (ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]" " space"); return; } /* * If `any_segs' is still FALSE, we must define a default * segment. */ if (!any_segs) { int tempint; /* ignored */ if (segto != obj_segment("__NASMDEFSEG", 2, &tempint)) error (ERR_PANIC, "strange segment conditions in OBJ driver"); } /* * Find the segment we are targetting. */ for (seg = seghead; seg; seg = seg->next) if (seg->index == segto) break; if (!seg) error (ERR_PANIC, "code directed to nonexistent segment?"); orp = seg->orp; orp->parm[0] = seg->currentpos; size = type & OUT_SIZMASK; realtype = type & OUT_TYPMASK; if (realtype == OUT_RAWDATA) { ucdata = data; while (size > 0) { unsigned int len; orp = obj_check(seg->orp, 1); len = RECORD_MAX - orp->used; if (len > size) len = size; memcpy (orp->buf+orp->used, ucdata, len); orp->committed = orp->used += len; orp->parm[0] = seg->currentpos += len; ucdata += len; size -= len; } } else if (realtype == OUT_ADDRESS || realtype == OUT_REL2ADR || realtype == OUT_REL4ADR) { int rsize; if (segment == NO_SEG && realtype != OUT_ADDRESS) error(ERR_NONFATAL, "relative call to absolute address not" " supported by OBJ format"); if (segment >= SEG_ABS) error(ERR_NONFATAL, "far-absolute relocations not supported" " by OBJ format"); ldata = *(long *)data; if (realtype == OUT_REL2ADR) { ldata += (size-2); size = 2; } if (realtype == OUT_REL4ADR) { ldata += (size-4); size = 4; } if (size == 2) orp = obj_word (orp, ldata); else orp = obj_dword (orp, ldata); rsize = size; if (segment < SEG_ABS && (segment != NO_SEG && segment % 2) && size == 4) { /* * This is a 4-byte segment-base relocation such as * `MOV EAX,SEG foo'. OBJ format can't actually handle * these, but if the constant term has the 16 low bits * zero, we can just apply a 2-byte segment-base * relocation to the low word instead. */ rsize = 2; if (ldata & 0xFFFF) error(ERR_NONFATAL, "OBJ format cannot handle complex" " dword-size segment base references"); } if (segment != NO_SEG) obj_write_fixup (orp, rsize, (realtype == OUT_ADDRESS ? 0x4000 : 0), segment, wrt, seg); seg->currentpos += size; } else if (realtype == OUT_RESERVE) { if (orp->committed) orp = obj_bump(orp); seg->currentpos += size; } obj_commit(orp);}static void obj_write_fixup (ObjRecord *orp, int bytes, int segrel, long seg, long wrt, struct Segment *segto){ unsigned locat; int method; int base; long tidx, fidx; struct Segment *s = NULL; struct Group *g = NULL; struct External *e = NULL; ObjRecord *forp; if (bytes == 1) { error(ERR_NONFATAL, "`obj' output driver does not support" " one-byte relocations"); return; } forp = orp->child; if (forp == NULL) { orp->child = forp = obj_new(); forp->up = &(orp->child); /* We should choose between FIXUPP and FIXU32 record type */ /* If we're targeting a 32-bit segment, use a FIXU32 record */ if (segto->use32) forp->type = FIXU32; else forp->type = FIXUPP; } if (seg % 2) { base = TRUE; locat = FIX_16_SELECTOR; seg--; if (bytes != 2) error(ERR_PANIC, "OBJ: 4-byte segment base fixup got" " through sanity check"); } else { base = FALSE; locat = (bytes == 2) ? FIX_16_OFFSET : FIX_32_OFFSET; if (!segrel) /* * There is a bug in tlink that makes it process self relative * fixups incorrectly if the x_size doesn't match the location * size. */ forp = obj_force(forp, bytes<<3); } forp = obj_rword (forp, locat | segrel | (orp->parm[0]-orp->parm[2])); tidx = fidx = -1, method = 0; /* placate optimisers */ /* * See if we can find the segment ID in our segment list. If * so, we have a T4 (LSEG) target. */ for (s = seghead; s; s = s->next) if (s->index == seg) break; if (s) method = 4, tidx = s->obj_index; else { for (g = grphead; g; g = g->next) if (g->index == seg) break; if (g) method = 5, tidx = g->obj_index; else { long i = seg/2; struct ExtBack *eb = ebhead; while (i > EXT_BLKSIZ) { if (eb) eb = eb->next; else break; i -= EXT_BLKSIZ; } if (eb) method = 6, e = eb->exts[i], tidx = e->index; else error(ERR_PANIC, "unrecognised segment value in obj_write_fixup"); } } /* * If no WRT given, assume the natural default, which is method * F5 unless: * * - we are doing an OFFSET fixup for a grouped segment, in * which case we require F1 (group). * * - we are doing an OFFSET fixup for an external with a * default WRT, in which case we must honour the default WRT. */ if (wrt == NO_SEG) { if (!base && s && s->grp) method |= 0x10, fidx = s->grp->obj_index; else if (!base && e && e->defwrt_type != DEFWRT_NONE) { if (e->defwrt_type == DEFWRT_SEGMENT) method |= 0x00, fidx = e->defwrt_ptr.seg->obj_index; else if (e->defwrt_type == DEFWRT_GROUP) method |= 0x10, fidx = e->defwrt_ptr.grp->obj_index; else { error(ERR_NONFATAL, "default WRT specification for" " external `%s' unresolved", e->name); method |= 0x50, fidx = -1; /* got to do _something_ */ } } else method |= 0x50, fidx = -1; } else { /* * See if we can find the WRT-segment ID in our segment * list. If so, we have a F0 (LSEG) frame. */ for (s = seghead; s; s = s->next) if (s->index == wrt-1) break; if (s) method |= 0x00, fidx = s->obj_index; else { for (g = grphead; g; g = g->next) if (g->index == wrt-1) break; if (g) method |= 0x10, fidx = g->obj_index; else { long i = wrt/2; struct ExtBack *eb = ebhead; while (i > EXT_BLKSIZ) { if (eb) eb = eb->next; else break; i -= EXT_BLKSIZ; } if (eb) method |= 0x20, fidx = eb->exts[i]->index; else error(ERR_PANIC, "unrecognised WRT value in obj_write_fixup"); } } } forp = obj_byte (forp, method); if (fidx != -1) forp = obj_index (forp, fidx); forp = obj_index (forp, tidx); obj_commit (forp);}static long obj_segment (char *name, int pass, int *bits) { /* * We call the label manager here to define a name for the new * segment, and when our _own_ label-definition stub gets * called in return, it should register the new segment name * using the pointer it gets passed. That way we save memory, * by sponging off the label manager. */#if defined(DEBUG) && DEBUG>=3fprintf(stderr," obj_segment: < %s >, pass=%d, *bits=%d\n", name, pass, *bits);#endif if (!name) { *bits = 16; current_seg = NULL; return first_seg; } else { struct Segment *seg; struct Group *grp; struct External **extp; int obj_idx, i, attrs, rn_error; char *p; /* * Look for segment attributes. */ attrs = 0; while (*name == '.') name++; /* hack, but a documented one */ p = name; while (*p && !isspace(*p)) p++; if (*p) { *p++ = '\0'; while (*p && isspace(*p)) *p++ = '\0'; } while (*p) { while (*p && !isspace(*p)) p++; if (*p) { *p++ = '\0'; while (*p && isspace(*p)) *p++ = '\0'; } attrs++; } obj_idx = 1; for (seg = seghead; seg; seg = seg->next) { obj_idx++; if (!strcmp(seg->name, name)) { if (attrs > 0 && pass == 1) error(ERR_WARNING, "segment attributes specified on" " redeclaration of segment: ignoring"); if (seg->use32) *bits = 32; else *bits = 16; current_seg = seg; return seg->index; } } *segtail = seg = nasm_malloc(sizeof(*seg)); seg->next = NULL; segtail = &seg->next; seg->index = (any_segs ? seg_alloc() : first_seg); seg->obj_index = obj_idx; seg->grp = NULL; any_segs = TRUE; seg->name = NULL; seg->currentpos = 0; seg->align = 1; /* default */ seg->use32 = FALSE; /* default */ seg->combine = CMB_PUBLIC; /* default */ seg->segclass = seg->overlay = NULL; seg->pubhead = NULL; seg->pubtail = &seg->pubhead; seg->lochead = NULL; seg->loctail = &seg->lochead; seg->orp = obj_new(); seg->orp->up = &(seg->orp); seg->orp->ori = ori_ledata; seg->orp->type = LEDATA; seg->orp->parm[1] = obj_idx; /* * Process the segment attributes. */ p = name; while (attrs--) { p += strlen(p); while (!*p) p++; /* * `p' contains a segment attribute. */ if (!nasm_stricmp(p, "private")) seg->combine = CMB_PRIVATE; else if (!nasm_stricmp(p, "public")) seg->combine = CMB_PUBLIC; else if (!nasm_stricmp(p, "common")) seg->combine = CMB_COMMON; else if (!nasm_stricmp(p, "stack")) seg->combine = CMB_STACK; else if (!nasm_stricmp(p, "use16")) seg->use32 = FALSE; else if (!nasm_stricmp(p, "use32")) seg->use32 = TRUE; else if (!nasm_stricmp(p, "flat")) { /* * This segment is an OS/2 FLAT segment. That means * that its default group is group FLAT, even if * the group FLAT does not explicitly _contain_ the * segment. * * When we see this, we must create the group * `FLAT', containing no segments, if it does not * already exist; then we must set the default * group of this segment to be the FLAT group. */ struct Group *grp; for (grp = grphead; grp; grp = grp->next) if (!strcmp(grp->name, "FLAT")) break; if (!grp) { obj_directive ("group", "FLAT", 1); for (grp = grphead; grp; grp = grp->next) if (!strcmp(grp->name, "FLAT")) break; if (!grp) error (ERR_PANIC, "failure to define FLAT?!"); } seg->grp = grp; } else if (!nasm_strnicmp(p, "class=", 6)) seg->segclass = nasm_strdup(p+6); else if (!nasm_strnicmp(p, "overlay=", 8)) seg->overlay = nasm_strdup(p+8); else if (!nasm_strnicmp(p, "align=", 6)) { seg->align = readnum(p+6, &rn_error); if (rn_error) { seg->align = 1; error (ERR_NONFATAL, "segment alignment should be" " numeric"); } switch ((int) seg->align) { case 1: /* BYTE */ case 2: /* WORD */ case 4: /* DWORD */ case 16: /* PARA */ case 256: /* PAGE */ case 4096: /* PharLap extension */ break; case 8: error(ERR_WARNING, "OBJ format does not support alignment" " of 8: rounding up to 16"); seg->align = 16; break; case 32: case 64: case 128: error(ERR_WARNING, "OBJ format does not support alignment" " of %d: rounding up to 256", seg->align); seg->align = 256; break; case 512: case 1024: case 2048: error(ERR_WARNING, "OBJ format does not support alignment" " of %d: rounding up to 4096", seg->align); seg->align = 4096; break; default: error(ERR_NONFATAL, "invalid alignment value %d", seg->align); seg->align = 1; break; } } else if (!nasm_strnicmp(p, "absolute=", 9)) { seg->align = SEG_ABS + readnum(p+9, &rn_error); if (rn_error) error (ERR_NONFATAL, "argument to `absolute' segment" " attribute should be numeric"); } } /* We need to know whenever we have at least one 32-bit segment */ obj_use32 |= seg->use32; obj_seg_needs_update = seg; if (seg->align >= SEG_ABS) deflabel (name, NO_SEG, seg->align - SEG_ABS, NULL, FALSE, FALSE, &of_obj, error); else deflabel (name, seg->index+1, 0L, NULL, FALSE, FALSE, &of_obj, error); obj_seg_needs_update = NULL; /* * See if this segment is defined in any groups. */ for (grp = grphead; grp; grp = grp->next) { for (i = grp->nindices; i < grp->nentries; i++) { if (!strcmp(grp->segs[i].name, seg->name)) { nasm_free (grp->segs[i].name); grp->segs[i] = grp->segs[grp->nindices]; grp->segs[grp->nindices++].index = seg->obj_index; if (seg->grp) error(ERR_WARNING, "segment `%s' is already part of" " a group: first one takes precedence", seg->name); else seg->grp = grp; } } } /* * Walk through the list of externals with unresolved * default-WRT clauses, and resolve any that point at this * segment. */ extp = &dws; while (*extp) { if ((*extp)->defwrt_type == DEFWRT_STRING && !strcmp((*extp)->defwrt_ptr.string, seg->name)) { nasm_free((*extp)->defwrt_ptr.string); (*extp)->defwrt_type = DEFWRT_SEGMENT; (*extp)->defwrt_ptr.seg = seg; *extp = (*extp)->next_dws; } else extp = &(*extp)->next_dws; } if (seg->use32) *bits = 32; else *bits = 16; current_seg = seg; return seg->index;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -