📄 outelf.c
字号:
/* outelf.c output routines for the Netwide Assembler to produce * ELF32 (i386 of course) object file format * * The Netwide Assembler is copyright (C) 1996 Simon Tatham and * Julian Hall. All rights reserved. The software is * redistributable under the licence given in the file "Licence" * distributed in the NASM archive. */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#include "nasm.h"#include "nasmlib.h"#include "outform.h"#ifdef OF_ELF/* * Relocation types. */enum reloc_type { R_386_32 = 1, /* ordinary absolute relocation */ R_386_PC32 = 2, /* PC-relative relocation */ R_386_GOT32 = 3, /* an offset into GOT */ R_386_PLT32 = 4, /* a PC-relative offset into PLT */ R_386_COPY = 5, /* ??? */ R_386_GLOB_DAT = 6, /* ??? */ R_386_JUMP_SLOT = 7, /* ??? */ R_386_RELATIVE = 8, /* ??? */ R_386_GOTOFF = 9, /* an offset from GOT base */ R_386_GOTPC = 10, /* a PC-relative offset _to_ GOT */ /* These are GNU extensions, but useful */ R_386_16 = 20, /* A 16-bit absolute relocation */ R_386_PC16 = 21, /* A 16-bit PC-relative relocation */ R_386_8 = 22, /* An 8-bit absolute relocation */ R_386_PC8 = 23 /* An 8-bit PC-relative relocation */};struct Reloc { struct Reloc *next; long address; /* relative to _start_ of section */ long symbol; /* ELF symbol info thingy */ int type; /* type of relocation */};struct Symbol { long strpos; /* string table position of name */ long section; /* section ID of the symbol */ int type; /* symbol type */ long value; /* address, or COMMON variable align */ long size; /* size of symbol */ long globnum; /* symbol table offset if global */ struct Symbol *next; /* list of globals in each section */ struct Symbol *nextfwd; /* list of unresolved-size symbols */ char *name; /* used temporarily if in above list */};#define SHT_PROGBITS 1#define SHT_NOBITS 8#define SHF_WRITE 1#define SHF_ALLOC 2#define SHF_EXECINSTR 4struct Section { struct SAA *data; unsigned long len, size, nrelocs; long index; int type; /* SHT_PROGBITS or SHT_NOBITS */ int align; /* alignment: power of two */ unsigned long flags; /* section flags */ char *name; struct SAA *rel; long rellen; struct Reloc *head, **tail; struct Symbol *gsyms; /* global symbols in section */};#define SECT_DELTA 32static struct Section **sects;static int nsects, sectlen;#define SHSTR_DELTA 256static char *shstrtab;static int shstrtablen, shstrtabsize;static struct SAA *syms;static unsigned long nlocals, nglobs;static long def_seg;static struct RAA *bsym;static struct SAA *strs;static unsigned long strslen;static FILE *elffp;static efunc error;static evalfunc evaluate;static struct Symbol *fwds;static char elf_module[FILENAME_MAX];extern struct ofmt of_elf;#define SHN_ABS 0xFFF1#define SHN_COMMON 0xFFF2#define SHN_UNDEF 0#define SYM_SECTION 0x04#define SYM_GLOBAL 0x10#define SYM_DATA 0x01#define SYM_FUNCTION 0x02#define GLOBAL_TEMP_BASE 16 /* bigger than any constant sym id */#define SEG_ALIGN 16 /* alignment of sections in file */#define SEG_ALIGN_1 (SEG_ALIGN-1)static const char align_str[SEG_ALIGN] = ""; /* ANSI will pad this with 0s */#define ELF_MAX_SECTIONS 16 /* really 10, but let's play safe */static struct ELF_SECTDATA { void *data; long len; int is_saa;} *elf_sects;static int elf_nsect;static long elf_foffs;static void elf_write(void);static void elf_sect_write(struct Section *, const unsigned char *, unsigned long);static void elf_section_header (int, int, int, void *, int, long, int, int, int, int);static void elf_write_sections (void);static struct SAA *elf_build_symtab (long *, long *);static struct SAA *elf_build_reltab (long *, struct Reloc *);static void add_sectname (char *, char *);/* this stuff is needed for the stabs debugging format */#define N_SO 0x64 /* ID for main source file */#define N_SOL 0x84 /* ID for sub-source file */#define N_BINCL 0x82#define N_EINCL 0xA2#define N_SLINE 0x44#define TY_STABSSYMLIN 0x40 /* ouch */struct stabentry { unsigned long n_strx; unsigned char n_type; unsigned char n_other; unsigned short n_desc; unsigned long n_value;};struct erel { int offset,info;};struct symlininfo { int offset; int section; /* section index */ char *name; /* shallow-copied pointer of section name */};struct linelist { struct symlininfo info; int line; char *filename; struct linelist * next; struct linelist * last;};static struct linelist *stabslines=0;static int stabs_immcall=0;static int currentline=0;static int numlinestabs=0;static char * stabs_filename=0;static int symtabsection;static unsigned char *stabbuf=0,*stabstrbuf=0,*stabrelbuf=0;static int stablen,stabstrlen,stabrellen;static struct dfmt df_stabs;void stabs_init(struct ofmt *,void *,FILE *,efunc );void stabs_linenum(const char *filename,long linenumber,long);void stabs_deflabel(char *,long ,long ,int ,char *);void stabs_directive(const char *,const char *);void stabs_typevalue(long );void stabs_output(int ,void *);void stabs_generate();void stabs_cleanup();/* end of stabs debugging stuff *//* * Special section numbers which are used to define ELF special * symbols, which can be used with WRT to provide PIC relocation * types. */static long elf_gotpc_sect, elf_gotoff_sect;static long elf_got_sect, elf_plt_sect;static long elf_sym_sect;static void elf_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval){ elffp = fp; error = errfunc; evaluate = eval; (void) ldef; /* placate optimisers */ sects = NULL; nsects = sectlen = 0; syms = saa_init((long)sizeof(struct Symbol)); nlocals = nglobs = 0; bsym = raa_init(); strs = saa_init(1L); saa_wbytes (strs, "\0", 1L); saa_wbytes (strs, elf_module, (long)(strlen(elf_module)+1)); strslen = 2+strlen(elf_module); shstrtab = NULL; shstrtablen = shstrtabsize = 0;; add_sectname ("", ""); fwds = NULL; elf_gotpc_sect = seg_alloc(); ldef("..gotpc", elf_gotpc_sect+1, 0L, NULL, FALSE, FALSE, &of_elf, error); elf_gotoff_sect = seg_alloc(); ldef("..gotoff", elf_gotoff_sect+1, 0L, NULL, FALSE, FALSE,&of_elf,error); elf_got_sect = seg_alloc(); ldef("..got", elf_got_sect+1, 0L, NULL, FALSE, FALSE, &of_elf, error); elf_plt_sect = seg_alloc(); ldef("..plt", elf_plt_sect+1, 0L, NULL, FALSE, FALSE, &of_elf, error); elf_sym_sect = seg_alloc(); ldef("..sym", elf_sym_sect+1, 0L, NULL, FALSE, FALSE, &of_elf, error); def_seg = seg_alloc();}static void elf_cleanup(int debuginfo){ struct Reloc *r; int i; (void) debuginfo; elf_write(); fclose (elffp); for (i=0; i<nsects; i++) { if (sects[i]->type != SHT_NOBITS) saa_free (sects[i]->data); if (sects[i]->head) saa_free (sects[i]->rel); while (sects[i]->head) { r = sects[i]->head; sects[i]->head = sects[i]->head->next; nasm_free (r); } } nasm_free (sects); saa_free (syms); raa_free (bsym); saa_free (strs); if (of_elf.current_dfmt) { of_elf.current_dfmt->cleanup(); }}static void add_sectname (char *firsthalf, char *secondhalf){ int len = strlen(firsthalf)+strlen(secondhalf); while (shstrtablen + len + 1 > shstrtabsize) shstrtab = nasm_realloc (shstrtab, (shstrtabsize += SHSTR_DELTA)); strcpy (shstrtab+shstrtablen, firsthalf); strcat (shstrtab+shstrtablen, secondhalf); shstrtablen += len+1;}static int elf_make_section (char *name, int type, int flags, int align){ struct Section *s; s = nasm_malloc (sizeof(*s)); if (type != SHT_NOBITS) s->data = saa_init (1L); s->head = NULL; s->tail = &s->head; s->len = s->size = 0; s->nrelocs = 0; if (!strcmp(name, ".text")) s->index = def_seg; else s->index = seg_alloc(); add_sectname ("", name); s->name = nasm_malloc (1+strlen(name)); strcpy (s->name, name); s->type = type; s->flags = flags; s->align = align; s->gsyms = NULL; if (nsects >= sectlen) sects = nasm_realloc (sects, (sectlen += SECT_DELTA)*sizeof(*sects)); sects[nsects++] = s; return nsects-1;}static long elf_section_names (char *name, int pass, int *bits){ char *p; int flags_and, flags_or, type, align, i; /* * Default is 32 bits. */ if (!name) { *bits = 32; return def_seg; } p = name; while (*p && !isspace(*p)) p++; if (*p) *p++ = '\0'; flags_and = flags_or = type = align = 0; while (*p && isspace(*p)) p++; while (*p) { char *q = p; while (*p && !isspace(*p)) p++; if (*p) *p++ = '\0'; while (*p && isspace(*p)) p++; if (!nasm_strnicmp(q, "align=", 6)) { align = atoi(q+6); if (align == 0) align = 1; if ( (align-1) & align ) { /* means it's not a power of two */ error (ERR_NONFATAL, "section alignment %d is not" " a power of two", align); align = 1; } } else if (!nasm_stricmp(q, "alloc")) { flags_and |= SHF_ALLOC; flags_or |= SHF_ALLOC; } else if (!nasm_stricmp(q, "noalloc")) { flags_and |= SHF_ALLOC; flags_or &= ~SHF_ALLOC; } else if (!nasm_stricmp(q, "exec")) { flags_and |= SHF_EXECINSTR; flags_or |= SHF_EXECINSTR; } else if (!nasm_stricmp(q, "noexec")) { flags_and |= SHF_EXECINSTR; flags_or &= ~SHF_EXECINSTR; } else if (!nasm_stricmp(q, "write")) { flags_and |= SHF_WRITE; flags_or |= SHF_WRITE; } else if (!nasm_stricmp(q, "nowrite")) { flags_and |= SHF_WRITE; flags_or &= ~SHF_WRITE; } else if (!nasm_stricmp(q, "progbits")) { type = SHT_PROGBITS; } else if (!nasm_stricmp(q, "nobits")) { type = SHT_NOBITS; } } if (!strcmp(name, ".comment") || !strcmp(name, ".shstrtab") || !strcmp(name, ".symtab") || !strcmp(name, ".strtab")) { error (ERR_NONFATAL, "attempt to redefine reserved section" "name `%s'", name); return NO_SEG; } for (i=0; i<nsects; i++) if (!strcmp(name, sects[i]->name)) break; if (i == nsects) { if (!strcmp(name, ".text")) i = elf_make_section (name, SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR, 16); else if (!strcmp(name, ".rodata")) i = elf_make_section (name, SHT_PROGBITS, SHF_ALLOC, 4); else if (!strcmp(name, ".data")) i = elf_make_section (name, SHT_PROGBITS, SHF_ALLOC | SHF_WRITE, 4); else if (!strcmp(name, ".bss")) i = elf_make_section (name, SHT_NOBITS, SHF_ALLOC | SHF_WRITE, 4); else i = elf_make_section (name, SHT_PROGBITS, SHF_ALLOC, 1); if (type) sects[i]->type = type; if (align) sects[i]->align = align; sects[i]->flags &= ~flags_and; sects[i]->flags |= flags_or; } else if (pass == 1) { if (type || align || flags_and) error (ERR_WARNING, "section attributes ignored on" " redeclaration of section `%s'", name); } return sects[i]->index;}static void elf_deflabel (char *name, long segment, long offset, int is_global, char *special){ int pos = strslen; struct Symbol *sym; int special_used = FALSE;#if defined(DEBUG) && DEBUG>2fprintf(stderr, " elf_deflabel: %s, seg=%ld, off=%ld, is_global=%d, %s\n", name, segment, offset, is_global, special);#endif if (name[0] == '.' && name[1] == '.' && name[2] != '@') { /* * This is a NASM special symbol. We never allow it into * the ELF symbol table, even if it's a valid one. If it * _isn't_ a valid one, we should barf immediately. */ if (strcmp(name, "..gotpc") && strcmp(name, "..gotoff") && strcmp(name, "..got") && strcmp(name, "..plt") && strcmp(name, "..sym")) error (ERR_NONFATAL, "unrecognised special symbol `%s'", name); return; } if (is_global == 3) { struct Symbol **s; /* * Fix up a forward-reference symbol size from the first * pass. */ 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++)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -