📄 outobj.c
字号:
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;
}
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) {
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",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -