📄 outobj.c
字号:
int len;
special += 3;
special += strspn(special, " \t");
p = nasm_strndup(special, len = strcspn(special, ":"));
obj_ext_set_defwrt (ext, p);
special += len;
if (*special && *special != ':')
error(ERR_NONFATAL, "`:' expected in special symbol"
" text for `%s'", ext->name);
else if (*special == ':')
special++;
}
/*
* The NEAR or FAR keywords specify nearness or
* farness. FAR gives default element size 1.
*/
if (!nasm_strnicmp(special, "far", 3)) {
if (ext->commonsize)
ext->commonelem = 1;
else
error(ERR_NONFATAL, "`%s': `far' keyword may only be applied"
" to common variables\n", ext->name);
special += 3;
special += strspn(special, " \t");
} else if (!nasm_strnicmp(special, "near", 4)) {
if (ext->commonsize)
ext->commonelem = 0;
else
error(ERR_NONFATAL, "`%s': `far' keyword may only be applied"
" to common variables\n", ext->name);
special += 4;
special += strspn(special, " \t");
}
/*
* If it's a common, and anything else remains on the line
* before a further colon, evaluate it as an expression and
* use that as the element size. Forward references aren't
* allowed.
*/
if (*special == ':')
special++;
else if (*special) {
if (ext->commonsize) {
expr *e;
struct tokenval tokval;
stdscan_reset();
stdscan_bufptr = special;
tokval.t_type = TOKEN_INVALID;
e = evaluate(stdscan, NULL, &tokval, NULL, 1, error, NULL);
if (e) {
if (!is_simple(e))
error (ERR_NONFATAL, "cannot use relocatable"
" expression as common-variable element size");
else
ext->commonelem = reloc_value(e);
}
special = stdscan_bufptr;
} else {
error (ERR_NONFATAL, "`%s': element-size specifications only"
" apply to common variables", ext->name);
while (*special && *special != ':')
special++;
if (*special == ':')
special++;
}
}
}
i = segment/2;
eb = ebhead;
if (!eb) {
eb = *ebtail = nasm_malloc(sizeof(*eb));
eb->next = NULL;
ebtail = &eb->next;
}
while (i >= EXT_BLKSIZ) {
if (eb && eb->next)
eb = eb->next;
else {
eb = *ebtail = nasm_malloc(sizeof(*eb));
eb->next = NULL;
ebtail = &eb->next;
}
i -= EXT_BLKSIZ;
}
eb->exts[i] = ext;
ext->index = ++externals;
if (special && !used_special)
error(ERR_NONFATAL, "OBJ supports no special symbol features"
" for this symbol type");
}
/* forward declaration */
static void obj_write_fixup (ObjRecord *orp, int bytes,
int segrel, long seg, long wrt, struct Segment *segto);
static void obj_out (long segto, const void *data, unsigned long type,
long segment, long wrt)
{
unsigned long size, realtype;
const unsigned char *ucdata;
long ldata;
struct Segment *seg;
ObjRecord *orp;
/*
* 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) {
/* DAL */
while (size) {
unsigned int len ;
orp = obj_check(seg->orp, 1);
len = RECORD_MAX - orp->used;
if (len > size)
len = size;
memset (orp->buf+orp->used, 0, len);
orp->committed = orp->used += len;
orp->parm[0] = seg->currentpos += len;
size -= len ;
}
/* end DAL */
}
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;
/* DAL */
if (seg & 0xc0000)
method = 0x50, tidx = seg ;
else
/* end DAL */
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) { /* BUG FIX, DAL make it >= */
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>=3
fprintf(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) {
/* DAL */
if (seg->combine != CMB_BORLANDVIRTUAL)
/* end DAL */
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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -