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

📄 outelf.c

📁 一个汇编语言编译器源码
💻 C
📖 第 1 页 / 共 3 页
字号:
	 */
	for (s = &fwds; *s; s = &(*s)->nextfwd)
	    if (!strcmp((*s)->name, name)) {
		struct tokenval tokval;
		expr *e;
		char *p = special;

		while (*p && !isspace(*p)) p++;
		while (*p && isspace(*p)) p++;
		stdscan_reset();
		stdscan_bufptr = p;
		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 symbol size");
		    else
			(*s)->size = reloc_value(e);
		}

		/*
		 * Remove it from the list of unresolved sizes.
		 */
		nasm_free ((*s)->name);
		*s = (*s)->nextfwd;
		return;
	    }
	return;			       /* it wasn't an important one */
    }

    saa_wbytes (strs, name, (long)(1+strlen(name)));
    strslen += 1+strlen(name);

    sym = saa_wstruct (syms);

    sym->strpos = pos;
    sym->type = is_global ? SYM_GLOBAL : 0;
    sym->size = 0;
    if (segment == NO_SEG)
	sym->section = SHN_ABS;
    else {
	int i;
	sym->section = SHN_UNDEF;
	if (nsects == 0 && segment == def_seg) {
	    int tempint;
	    if (segment != elf_section_names (".text", 2, &tempint))
		error (ERR_PANIC, "strange segment conditions in ELF driver");
	    sym->section = nsects;
	} else {
	    for (i=0; i<nsects; i++)
		if (segment == sects[i]->index) {
		    sym->section = i+1;
		    break;
		}
	}
    }

    if (is_global == 2) {
	sym->size = offset;
	sym->value = 0;
	sym->section = SHN_COMMON;
	/*
	 * We have a common variable. Check the special text to see
	 * if it's a valid number and power of two; if so, store it
	 * as the alignment for the common variable.
	 */
	if (special) {
	    int err;
	    sym->value = readnum (special, &err);
	    if (err)
		error(ERR_NONFATAL, "alignment constraint `%s' is not a"
		      " valid number", special);
	    else if ( (sym->value | (sym->value-1)) != 2*sym->value - 1)
		error(ERR_NONFATAL, "alignment constraint `%s' is not a"
		      " power of two", special);
	}
	special_used = TRUE;
    } else
	sym->value = (sym->section == SHN_UNDEF ? 0 : offset);

    if (sym->type == SYM_GLOBAL) {
	/*
	 * There's a problem here that needs fixing. 
	 * If sym->section == SHN_ABS, then the first line of the
	 * else section causes a core dump, because its a reference
	 * beyond the end of the section array.
	 * This behaviour is exhibited by this code:
	 *     GLOBAL crash_nasm
	 *     crash_nasm equ 0
	 *
	 * I'm not sure how to procede, because I haven't got the
	 * first clue about how ELF works, so I don't know what to
	 * do with it. Furthermore, I'm not sure what the rest of this
	 * section of code does. Help?
	 *
	 * For now, I'll see if doing absolutely nothing with it will
	 * work...
	 */
	if (sym->section == SHN_UNDEF || sym->section == SHN_COMMON)
	{
	    bsym = raa_write (bsym, segment, nglobs);
	}
	else if (sym->section != SHN_ABS) 
	{
	    /*
	     * This is a global symbol; so we must add it to the linked
	     * list of global symbols in its section. We'll push it on
	     * the beginning of the list, because it doesn't matter
	     * much which end we put it on and it's easier like this.
	     *
	     * In addition, we check the special text for symbol
	     * type and size information.
	     */
	    sym->next = sects[sym->section-1]->gsyms;
	    sects[sym->section-1]->gsyms = sym;

	    if (special) {
		int n = strcspn(special, " ");

		if (!nasm_strnicmp(special, "function", n))
		    sym->type |= SYM_FUNCTION;
		else if (!nasm_strnicmp(special, "data", n) ||
			 !nasm_strnicmp(special, "object", n))
		    sym->type |= SYM_DATA;
		else
		    error(ERR_NONFATAL, "unrecognised symbol type `%.*s'",
			  n, special);
		if (special[n]) {
		    struct tokenval tokval;
		    expr *e;
		    int fwd = FALSE;

		    while (special[n] && isspace(special[n]))
			n++;
		    /*
		     * We have a size expression; attempt to
		     * evaluate it.
		     */
		    stdscan_reset();
		    stdscan_bufptr = special+n;
		    tokval.t_type = TOKEN_INVALID;
		    e = evaluate(stdscan, NULL, &tokval, &fwd, 0, error, NULL);
		    if (fwd) {
			sym->nextfwd = fwds;
			fwds = sym;
			sym->name = nasm_strdup(name);
		    } else if (e) {
			if (!is_simple(e))
			    error (ERR_NONFATAL, "cannot use relocatable"
				   " expression as symbol size");
			else
			    sym->size = reloc_value(e);
		    }
		}
		special_used = TRUE;
	    }
	}
	sym->globnum = nglobs;
	nglobs++;
    } else
	nlocals++;

    if (special && !special_used)
	error(ERR_NONFATAL, "no special symbol features supported here");
}

static void elf_add_reloc (struct Section *sect, long segment,
			   int type) 
{
    struct Reloc *r;

    r = *sect->tail = nasm_malloc(sizeof(struct Reloc));
    sect->tail = &r->next;
    r->next = NULL;

    r->address = sect->len;
    if (segment == NO_SEG)
	r->symbol = 2;
    else {
	int i;
	r->symbol = 0;
	for (i=0; i<nsects; i++)
	    if (segment == sects[i]->index)
		r->symbol = i+3;
	if (!r->symbol)
	    r->symbol = GLOBAL_TEMP_BASE + raa_read(bsym, segment);
    }
    r->type = type;

    sect->nrelocs++;
}

/*
 * This routine deals with ..got and ..sym relocations: the more
 * complicated kinds. In shared-library writing, some relocations
 * with respect to global symbols must refer to the precise symbol
 * rather than referring to an offset from the base of the section
 * _containing_ the symbol. Such relocations call to this routine,
 * which searches the symbol list for the symbol in question.
 *
 * R_386_GOT32 references require the _exact_ symbol address to be
 * used; R_386_32 references can be at an offset from the symbol.
 * The boolean argument `exact' tells us this.
 *
 * Return value is the adjusted value of `addr', having become an
 * offset from the symbol rather than the section. Should always be
 * zero when returning from an exact call.
 *
 * Limitation: if you define two symbols at the same place,
 * confusion will occur.
 *
 * Inefficiency: we search, currently, using a linked list which
 * isn't even necessarily sorted.
 */
static long elf_add_gsym_reloc (struct Section *sect,
				long segment, long offset,
				int type, int exact) 
{
    struct Reloc *r;
    struct Section *s;
    struct Symbol *sym, *sm;
    int i;

    /*
     * First look up the segment/offset pair and find a global
     * symbol corresponding to it. If it's not one of our segments,
     * then it must be an external symbol, in which case we're fine
     * doing a normal elf_add_reloc after first sanity-checking
     * that the offset from the symbol is zero.
     */
    s = NULL;
    for (i=0; i<nsects; i++)
	if (segment == sects[i]->index) {
	    s = sects[i];
	    break;
	}
    if (!s) {
	if (exact && offset != 0)
	    error (ERR_NONFATAL, "unable to find a suitable global symbol"
		   " for this reference");
	else
	    elf_add_reloc (sect, segment, type);
	return offset;
    }

    if (exact) {
	/*
	 * Find a symbol pointing _exactly_ at this one.
	 */
	for (sym = s->gsyms; sym; sym = sym->next)
	    if (sym->value == offset)
		break;
    } else {
	/*
	 * Find the nearest symbol below this one.
	 */
	sym = NULL;
	for (sm = s->gsyms; sm; sm = sm->next)
	    if (sm->value <= offset && (!sym || sm->value > sym->value))
		sym = sm;
    }
    if (!sym && exact) {
	error (ERR_NONFATAL, "unable to find a suitable global symbol"
	       " for this reference");
	return 0;
    }

    r = *sect->tail = nasm_malloc(sizeof(struct Reloc));
    sect->tail = &r->next;
    r->next = NULL;

    r->address = sect->len;
    r->symbol = GLOBAL_TEMP_BASE + sym->globnum;
    r->type = type;

    sect->nrelocs++;

    return offset - sym->value;
}

static void elf_out (long segto, void *data, unsigned long type,
		      long segment, long wrt) 
{
    struct Section *s;
    long realbytes = type & OUT_SIZMASK;
    long addr;
    unsigned char mydata[4], *p;
    int i;

    type &= OUT_TYPMASK;

    /*
     * handle absolute-assembly (structure definitions)
     */
    if (segto == NO_SEG) {
	if (type != OUT_RESERVE)
	    error (ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]"
		   " space");
	return;
    }

    s = NULL;
    for (i=0; i<nsects; i++)
	if (segto == sects[i]->index) {
	    s = sects[i];
	    break;
	}
    if (!s) {
	int tempint;		       /* ignored */
	if (segto != elf_section_names (".text", 2, &tempint))
	    error (ERR_PANIC, "strange segment conditions in ELF driver");
	else
	    s = sects[nsects-1];
    }

    if (s->type == SHT_NOBITS && type != OUT_RESERVE) {
	error(ERR_WARNING, "attempt to initialise memory in"
	      " BSS section `%s': ignored", s->name);
	if (type == OUT_REL2ADR)
	    realbytes = 2;
	else if (type == OUT_REL4ADR)
	    realbytes = 4;
	s->len += realbytes;
	return;
    }

    if (type == OUT_RESERVE) {
	if (s->type == SHT_PROGBITS) {
	    error(ERR_WARNING, "uninitialised space declared in"
		  " non-BSS section `%s': zeroing", s->name);
	    elf_sect_write (s, NULL, realbytes);
	} else
	    s->len += realbytes;
    } else if (type == OUT_RAWDATA) {
	if (segment != NO_SEG)
	    error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG");
	elf_sect_write (s, data, realbytes);
    } else if (type == OUT_ADDRESS) {
	addr = *(long *)data;
	if (segment != NO_SEG) {
	    if (segment % 2) {
		error(ERR_NONFATAL, "ELF format does not support"
		      " segment base references");
	    } else {
		if (wrt == NO_SEG) {
		    elf_add_reloc (s, segment, R_386_32);
		} else if (wrt == elf_gotpc_sect+1) {
		    /*
		     * The user will supply GOT relative to $$. ELF
		     * will let us have GOT relative to $. So we
		     * need to fix up the data item by $-$$.
		     */
		    addr += s->len;
		    elf_add_reloc (s, segment, R_386_GOTPC);
		} else if (wrt == elf_gotoff_sect+1) {
		    elf_add_reloc (s, segment, R_386_GOTOFF);
		} else if (wrt == elf_got_sect+1) {
		    addr = elf_add_gsym_reloc (s, segment, addr,
					       R_386_GOT32, TRUE);
		} else if (wrt == elf_sym_sect+1) {
		    addr = elf_add_gsym_reloc (s, segment, addr,
					       R_386_32, FALSE);
		} else if (wrt == elf_plt_sect+1) {
		    error(ERR_NONFATAL, "ELF format cannot produce non-PC-"
			  "relative PLT references");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -