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

📄 outobj.c

📁 开源的nasm编译器源码,研究编译器原理很有帮且
💻 C
📖 第 1 页 / 共 5 页
字号:
    /*     * 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 + -