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

📄 outelf.c

📁 一个免费的汇编语言编译器的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		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;
		    char *saveme=stdscan_bufptr;   /* bugfix? fbk 8/10/00 */

		    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);
		    }
		    stdscan_bufptr=saveme;    /* bugfix? fbk 8/10/00 */
		}
		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, const 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;
    static struct symlininfo sinfo;

    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];
	  i=nsects-1;
	}
    }

    /* again some stabs debugging stuff */
    if (of_elf.current_dfmt) {
      sinfo.offset=s->len;
      sinfo.section=i;
      sinfo.name=s->name;
      of_elf.current_dfmt->debug_output(TY_STABSSYMLIN,&sinfo);
    }
    /* end of debugging stuff */

    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) {
        int gnu16 = 0;
	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) {
		  if ( realbytes == 2 ) {
		    gnu16 = 1;
		    elf_add_reloc (s, segment, R_386_16);
		  } else {
		    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) {
		  if ( realbytes == 2 ) {
		    gnu16 = 1;
		    addr = elf_add_gsym_reloc (s, segment, addr,
					       R_386_16, FALSE);
		  } else {
		    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");
		} else {
		    error (ERR_NONFATAL, "ELF format does not support this"
			   " use of WRT");
		    wrt = NO_SEG;      /* we can at least _try_ to continue */
		}
	    }
	}
	p = mydata;
	if (gnu16) {
	    error(ERR_WARNING|ERR_WARN_GNUELF,
		  "16-bit relocations in ELF is a GNU extension");
	  WRITESHORT (p, addr);
	} else {
	  if (realbytes != 4 && segment != NO_SEG) {
	    error (ERR_NONFATAL, "Unsupported non-32-bit ELF relocation");
	  }
	  WRITELONG (p, addr);
	}
	elf_sect_write (s, mydata, realbytes);
    } else if (type == OUT_REL2ADR) {
	if (segment == segto)
	    error(ERR_PANIC, "intra-segment OUT_REL2ADR");
	if (segment != NO_SEG && segment % 2) {
	    error(ERR_NONFATAL, "ELF format does not support"
		  " segment base references");
	} else {
	  if (wrt == NO_SEG) {
	        error (ERR_WARNING|ERR_WARN_GNUELF,
		       "16-bit relocations in ELF is a GNU extension");
	        elf_add_reloc (s, segment, R_386_PC16);
	    } else {
		error (ERR_NONFATAL, "Unsupported non-32-bit ELF relocation");
	    }
	}
	p = mydata;
	WRITESHORT (p, *(long*)data - realbytes);
	elf_sect_write (s, mydata, 2L);
    } else if (type == OUT_REL4ADR) {
	if (segment == segto)
	    error(ERR_PANIC, "intra-segment OUT_REL4ADR");
	if (segment != NO_SEG && 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_PC32);
	    } else if (wrt == elf_plt_sect+1) {
		elf_add_reloc (s, segment, R_386_PLT32);
	    } else if (wrt == elf_gotpc_sect+1 ||
		       wrt == elf_gotoff_sect+1 ||
		       wrt == elf_got_sect+1) {
		error(ERR_NONFATAL, "ELF format cannot produce PC-"
		      "relative GOT references");
	    } else {
		error (ERR_NONFATAL, "ELF format does not support this"
		       " use of WRT");
		wrt = NO_SEG;      /* we can at least _try_ to continue */
	    }
	}
	p = mydata;
	WRITELONG (p, *(long*)data - realbytes);
	elf_sect_write (s, mydata, 4L);
    }
}

static void elf_write(void)
{
    int nsections, align;
    int scount;
    char *p;
    int commlen;
    char comment[64];
    int i;

    struct SAA *symtab;
    long symtablen, symtablocal;

    /*
     * Work out how many sections we will have. We have SHN_UNDEF,
     * then the flexible user sections, then the four fixed
     * sections `.comment', `.shstrtab', `.symtab' and `.strtab',
     * then optionally relocation sections for the user sections.
     */
    if (of_elf.current_dfmt == &df_stabs)
      nsections=8;
    else
      nsections = 5;		       /* SHN_UNDEF and the fixed ones */

    add_sectname ("", ".comment");
    add_sectname ("", ".shstrtab");
    add_sectname ("", ".symtab");
    add_sectname ("", ".strtab");
    for (i=0; i<nsects; i++) {
	nsections++;		       /* for the section itself */
	if (sects[i]->head) {
	    nsections++;	       /* for its relocations */
	    add_sectname (".rel", sects[i]->name);
	}
    }

    if (of_elf.current_dfmt == &df_stabs) {
      /* in case the debug information is wanted, just add these three sections... */
      add_sectname("",".stab");
      add_sectname("",".stabstr");
      add_sectname(".rel",".stab");
    }

    /*
     * Do the comment.
     */
    *comment = '\0';
    commlen = 2+sprintf(comment+1, "The Netwide Assembler %s", NASM_VER);

    /*
     * Output the ELF header.
     */
    fwrite ("\177ELF\1\1\1\0\0\0\0\0\0\0\0\0", 16, 1, elffp);
    fwriteshort (1, elffp);	       /* ET_REL relocatable file */
    fwriteshort (3, elffp);	       /* EM_386 processor ID */
    fwritelong (1L, elffp);	       /* EV_CURRENT file format version */
    fwritelong (0L, elffp);	       /* no entry point */
    fwritelong (0L, elffp);	       /* no program header table */
    fwritelong (0x40L, elffp);	       /* section headers straight after
					* ELF header plus alignment */
    fwritelong (0L, elffp);	       /* 386 defines no special flags */
    fwriteshort (0x34, elffp);	       /* size of ELF header */
    fwriteshort (0, elffp);	       /* no program header table, again */
    fwriteshort (0, elffp);	       /* still no program header table */
    fwriteshort (0x28, elffp);	       /* size of section header */
    fwriteshort (nsections, elffp);    /* number of sections */
    fwriteshort (nsects+2, elffp);     /* string table section index for
					* section header table */
    fwritelong (0L, elffp);	       /* align to 0x40 bytes */
    fwritelong (0L, elffp);
    fwritelong (0L, elffp);

    /*
     * Build the symbol table and relocation tables.
     */
    symtab = elf_build_symtab (&symtablen, &symtablocal);
    for (i=0; i<nsects; i++)
	if (sects[i]->head)
	    sects[i]->rel = elf_build_reltab (&sects[i]->rellen,
					      sects[i]->head);

    /*
     * Now output the section header table.
     */

    elf_foffs = 0x40 + 0x28 * nsections;
    align = ((elf_foffs+SEG_ALIGN_1) & ~SEG_ALIGN_1) - elf_foffs;
    elf_foffs += align;
    elf_nsect = 0;
    elf_sects = nasm_malloc(sizeof(*elf_sects) * (2 * nsects + 10));

⌨️ 快捷键说明

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