⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 outobj.c

📁 一个免费的汇编语言编译器的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		    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 + -