📄 outobj.c
字号:
loc->name = nasm_strdup(name);
loc->offset = offset;
if (special)
error(ERR_NONFATAL,
"OBJ supports no special symbol features"
" for this symbol type");
return;
}
/*
* Case (iii).
*/
if (is_global) {
ext = *exttail = nasm_malloc(sizeof(*ext));
ext->next = NULL;
exttail = &ext->next;
ext->name = name;
/* Place by default all externs into the current segment */
ext->defwrt_type = DEFWRT_NONE;
/* 28-Apr-2002 - John Coffman
The following code was introduced on 12-Aug-2000, and breaks fixups
on code passed thru the MSC 5.1 linker (3.66) and MSC 6.00A linker
(5.10). It was introduced after FIXUP32 was added, and may be needed
for 32-bit segments. The following will get 16-bit segments working
again, and maybe someone can correct the 'if' condition which is
actually needed.
*/
#if 0
if (current_seg) {
#else
if (current_seg && current_seg->use32) {
if (current_seg->grp) {
ext->defwrt_type = DEFWRT_GROUP;
ext->defwrt_ptr.grp = current_seg->grp;
} else {
ext->defwrt_type = DEFWRT_SEGMENT;
ext->defwrt_ptr.seg = current_seg;
}
}
#endif
if (is_global == 2) {
ext->commonsize = offset;
ext->commonelem = 1; /* default FAR */
} else
ext->commonsize = 0;
} else
return;
/*
* Now process the special text, if any, to find default-WRT
* specifications and common-variable element-size and near/far
* specifications.
*/
while (special && *special) {
used_special = TRUE;
/*
* We might have a default-WRT specification.
*/
if (!nasm_strnicmp(special, "wrt", 3)) {
char *p;
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) {
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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -