📄 outelf.c
字号:
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 (§s[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 + -