/* output_elf.c ELF output driver for vasm */ /* (c) in 2002-2016 by Frank Wille */ #include "vasm.h" #include "output_elf.h" #include "stabs.h" #if ELFCPU && defined(OUTELF) static char *copyright="vasm ELF output module 2.6 (c) 2002-2016 Frank Wille"; static int keep_empty_sects; static int be,cpu,bits; static unsigned elfrelsize,shtreloc; static hashtable *elfsymhash; static struct list shdrlist,symlist,relalist; static struct StrTabList shstrlist,strlist,stabstrlist; static unsigned symtabidx,strtabidx,shstrtabidx; static unsigned symindex,shdrindex; static unsigned stabidx,stabstralign; static utaddr stablen; static char stabname[] = ".stab"; static unsigned addString(struct StrTabList *sl,char *s) { struct StrTabNode *sn = mymalloc(sizeof(struct StrTabNode)); unsigned idx = sl->index; sn->str = s; addtail(&(sl->l),&(sn->n)); sl->index += (unsigned)strlen(s) + 1; return idx; } static void init_lists(void) { elfsymhash = new_hashtable(ELFSYMHTABSIZE); initlist(&shdrlist); initlist(&symlist); initlist(&relalist); shstrlist.index = strlist.index = 0; initlist(&shstrlist.l); initlist(&strlist.l); symindex = shdrindex = stabidx = 0; addString(&shstrlist,emptystr); /* first string is always "" */ symtabidx = addString(&shstrlist,".symtab"); strtabidx = addString(&shstrlist,".strtab"); shstrtabidx = addString(&shstrlist,".shstrtab"); addString(&strlist,emptystr); if (!no_symbols && first_nlist) { initlist(&stabstrlist.l); addString(&stabstrlist,emptystr); } } static struct Shdr32Node *addShdr32(void) { struct Shdr32Node *s = mycalloc(sizeof(struct Shdr32Node)); addtail(&shdrlist,&(s->n)); shdrindex++; return s; } static struct Shdr64Node *addShdr64(void) { struct Shdr64Node *s = mycalloc(sizeof(struct Shdr64Node)); addtail(&shdrlist,&(s->n)); shdrindex++; return s; } static struct Symbol32Node *addSymbol32(char *name) { struct Symbol32Node *sn = mycalloc(sizeof(struct Symbol32Node)); hashdata data; addtail(&symlist,&(sn->n)); if (name) { sn->name = name; setval(be,sn->s.st_name,4,addString(&strlist,name)); } data.ptr = sn; sn->idx = symindex++; add_hashentry(elfsymhash,name?name:emptystr,data); return sn; } static struct Symbol64Node *addSymbol64(char *name) { struct Symbol64Node *sn = mycalloc(sizeof(struct Symbol64Node)); hashdata data; addtail(&symlist,&(sn->n)); if (name) { sn->name = name; setval(be,sn->s.st_name,4,addString(&strlist,name)); } data.ptr = sn; sn->idx = symindex++; add_hashentry(elfsymhash,name?name:emptystr,data); return sn; } static void newSym32(char *name,elfull value,elfull size,uint8_t bind, uint8_t type,unsigned shndx) { struct Symbol32Node *elfsym = addSymbol32(name); setval(be,elfsym->s.st_value,4,value); setval(be,elfsym->s.st_size,4,size); elfsym->s.st_info[0] = ELF32_ST_INFO(bind,type); setval(be,elfsym->s.st_shndx,2,shndx); } static void newSym64(char *name,elfull value,elfull size,uint8_t bind, uint8_t type,unsigned shndx) { struct Symbol64Node *elfsym = addSymbol64(name); setval(be,elfsym->s.st_value,8,value); setval(be,elfsym->s.st_size,8,size); elfsym->s.st_info[0] = ELF64_ST_INFO(bind,type); setval(be,elfsym->s.st_shndx,2,shndx); } static void addRel32(elfull o,elfull a,elfull i,elfull r) { if (RELA) { struct Rela32Node *rn = mymalloc(sizeof(struct Rela32Node)); setval(be,rn->r.r_offset,4,o); setval(be,rn->r.r_addend,4,a); setval(be,rn->r.r_info,4,ELF32_R_INFO(i,r)); addtail(&relalist,&(rn->n)); } else { struct Rel32Node *rn = mymalloc(sizeof(struct Rel32Node)); setval(be,rn->r.r_offset,4,o); setval(be,rn->r.r_info,4,ELF32_R_INFO(i,r)); addtail(&relalist,&(rn->n)); } } static void addRel64(elfull o,elfull a,elfull i,elfull r) { if (RELA) { struct Rela64Node *rn = mymalloc(sizeof(struct Rela64Node)); setval(be,rn->r.r_offset,8,o); setval(be,rn->r.r_addend,8,a); setval(be,rn->r.r_info,8,ELF64_R_INFO(i,r)); addtail(&relalist,&(rn->n)); } else { struct Rel64Node *rn = mymalloc(sizeof(struct Rel64Node)); setval(be,rn->r.r_offset,8,o); setval(be,rn->r.r_info,8,ELF64_R_INFO(i,r)); addtail(&relalist,&(rn->n)); } } static void *makeShdr32(elfull name,elfull type,elfull flags,elfull offset, elfull size,elfull info,elfull align,elfull entsize) { struct Shdr32Node *shn; shn = addShdr32(); setval(be,shn->s.sh_name,4,name); setval(be,shn->s.sh_type,4,type); setval(be,shn->s.sh_flags,4,flags); setval(be,shn->s.sh_offset,4,offset); setval(be,shn->s.sh_size,4,size); setval(be,shn->s.sh_info,4,info); setval(be,shn->s.sh_addralign,4,align); setval(be,shn->s.sh_entsize,4,entsize); /* @@@ set sh_addr to org? */ return shn; } static void *makeShdr64(elfull name,elfull type,elfull flags,elfull offset, elfull size,elfull info,elfull align,elfull entsize) { struct Shdr64Node *shn; shn = addShdr64(); setval(be,shn->s.sh_name,4,name); setval(be,shn->s.sh_type,4,type); setval(be,shn->s.sh_flags,8,flags); setval(be,shn->s.sh_offset,8,offset); setval(be,shn->s.sh_size,8,size); setval(be,shn->s.sh_info,4,info); setval(be,shn->s.sh_addralign,8,align); setval(be,shn->s.sh_entsize,8,entsize); /* @@@ set sh_addr to org? */ return shn; } static unsigned findelfsymbol(char *name) /* find symbol with given name in symlist, return its index */ { hashdata data; if (find_name(elfsymhash,name,&data)) return ((struct Symbol32Node *)data.ptr)->idx; return 0; } static void init_ident(unsigned char *id,uint8_t class) { static char elfid[4] = { 0x7f,'E','L','F' }; memcpy(&id[EI_MAG0],elfid,4); id[EI_CLASS] = class; id[EI_DATA] = be ? ELFDATA2MSB : ELFDATA2LSB; id[EI_VERSION] = EV_CURRENT; memset(&id[EI_PAD],0,EI_NIDENT-EI_PAD); } static uint32_t get_sec_type(section *s) /* scan section attributes for type */ { char *a = s->attr; if (!strncmp(s->name,".note",5)) return SHT_NOTE; while (*a) { switch (*a++) { case 'c': case 'd': return SHT_PROGBITS; case 'u': return SHT_NOBITS; } } #if 0 output_error(3,attr); /* section attributes not supported */ return SHT_NULL; #else return SHT_PROGBITS; #endif } static utaddr get_sec_flags(char *a) /* scan section attributes for flags (read, write, alloc, execute) */ { utaddr f = 0; while (*a) { switch (*a++) { case 'a': f |= SHF_ALLOC; break; case 'w': f |= SHF_WRITE; break; case 'x': f |= SHF_EXECINSTR; break; } } return f; } static uint8_t get_sym_info(symbol *s) /* determine symbol-info: function, object, section, etc. */ { switch (TYPE(s)) { case TYPE_OBJECT: return STT_OBJECT; case TYPE_FUNCTION: return STT_FUNC; case TYPE_SECTION: return STT_SECTION; case TYPE_FILE: return STT_FILE; } return STT_NOTYPE; } static unsigned get_sym_index(symbol *s) { if (s->flags & COMMON) return SHN_COMMON; if (s->type == IMPORT) return SHN_UNDEF; if (s->sec) return (unsigned)s->sec->idx; return SHN_ABS; } static utaddr get_reloc_type(rlist **rl, utaddr *roffset,taddr *addend,symbol **refsym) { rlist *rl2; utaddr mask; int pos,size; utaddr t = 0; *roffset = 0; *addend = 0; *refsym = NULL; #ifdef VASM_CPU_M68K #include "elf_reloc_68k.h" #endif #ifdef VASM_CPU_PPC #include "elf_reloc_ppc.h" #endif #ifdef VASM_CPU_ARM #include "elf_reloc_arm.h" #endif #ifdef VASM_CPU_X86 if (bytespertaddr == 8) { #include "elf_reloc_x86_64.h" } else { #include "elf_reloc_386.h" } #endif #ifdef VASM_CPU_JAGRISC #include "elf_reloc_jag.h" #endif if (!t) unsupp_reloc_error(*rl); return t; } static utaddr make_relocs(rlist *rl,utaddr pc, void (*newsym)(char *,elfull,elfull,uint8_t, uint8_t,unsigned), void (*addrel)(elfull,elfull,elfull,elfull)) /* convert all of an atom's relocations into ELF32/ELF64 relocs */ { utaddr ro = 0; if (rl) { do { utaddr rtype,offset; taddr addend; symbol *refsym; if (rtype = get_reloc_type(&rl,&offset,&addend,&refsym)) { if (LOCREF(refsym)) { /* this is a local relocation */ addrel(pc+offset,addend,refsym->sec->idx,rtype); ro += elfrelsize; } else if (EXTREF(refsym)) { /* this is an external symbol reference */ unsigned idx = findelfsymbol(refsym->name); if (idx == 0) { /* create a new symbol, which can be referenced */ idx = symindex; newsym(refsym->name,0,0,STB_GLOBAL,STT_NOTYPE,0); } addrel(pc+offset,addend,idx,rtype); ro += elfrelsize; } else ierror(0); } } while (rl = rl->next); } return ro; } static utaddr make_stabreloc(utaddr pc,struct stabdef *nlist, void (*newsym)(char *,elfull,elfull,uint8_t, uint8_t,unsigned), void (*addrel)(elfull,elfull,elfull,elfull)) { rlist dummyrl; rlist *rl = &dummyrl; nreloc nrel; utaddr rtype,offset; taddr addend; symbol *refsym; nrel.byteoffset = offsetof(struct nlist32,n_value); nrel.bitoffset = 0; nrel.size = bits; nrel.mask = ~0; nrel.addend = nlist->value; nrel.sym = nlist->base; rl->next = NULL; rl->reloc = &nrel; rl->type = REL_ABS; return make_relocs(rl,pc,newsym,addrel); } /* create .rel(a)XXX section header */ static void make_relsechdr(char *sname,utaddr roffs,utaddr len,unsigned idx, void *(*makeshdr)(elfull,elfull,elfull,elfull, elfull,elfull,elfull,elfull)) { char *rname = mymalloc(strlen(sname) + 6); if (RELA) sprintf(rname,".rela%s",sname); else sprintf(rname,".rel%s",sname); makeshdr(addString(&shstrlist,rname),shtreloc,0, roffs, /* relative offset - will be fixed later! */ len,idx,bytespertaddr,elfrelsize); } static utaddr prog_sec_hdrs(section *sec,utaddr soffset, void *(*makeshdr)(elfull,elfull,elfull,elfull, elfull,elfull,elfull,elfull), void (*newsym)(char *,elfull,elfull, uint8_t,uint8_t, unsigned)) { section *secp; struct stabdef *nlist = first_nlist; /* generate section headers for program sections */ for (secp=sec; secp; secp=secp->next) { if (keep_empty_sects || get_sec_size(secp)!=0 || (secp->flags & HAS_SYMBOLS)) { uint32_t type = get_sec_type(secp); /* add section base symbol */ newsym(NULL,0,0,STB_LOCAL,STT_SECTION,shdrindex); secp->idx = shdrindex; makeshdr(addString(&shstrlist,secp->name), type,get_sec_flags(secp->attr),soffset, get_sec_size(secp),0,secp->align,0); if (type != SHT_NOBITS) soffset += get_sec_size(secp); } else secp->idx = 0; } /* look for stabs (32 bits only) */ if (!no_symbols && bits==32 && nlist!=NULL) { struct Shdr32Node *shn; char *cuname = NULL; /* count them, set name of compilation unit */ while (nlist != NULL) { stablen++; if (nlist->type==N_SO && nlist->name.ptr!=NULL && *nlist->name.ptr!='\0') cuname = nlist->name.ptr; nlist = nlist->next; } /* add all symbol strings to .stabstr, cu name should be first(?) */ addString(&stabstrlist,cuname!=NULL?cuname:filename); nlist = first_nlist; while (nlist != NULL) { nlist->name.idx = nlist->name.ptr != NULL ? addString(&stabstrlist,nlist->name.ptr) : 0; nlist = nlist->next; } /* make .stab section, preceded by a compilation unit header (stablen+1) */ stabidx = shdrindex; shn = makeshdr(addString(&shstrlist,stabname),SHT_PROGBITS,0,soffset, (stablen+1)*sizeof(struct nlist32),0,4, sizeof(struct nlist32)); soffset += (stablen+1) * sizeof(struct nlist32); setval(be,shn->s.sh_link,4,shdrindex); /* associated .stabstr section */ /* make .stabstr section */ makeshdr(addString(&shstrlist,".stabstr"),SHT_STRTAB,0,soffset, stabstrlist.index,0,1,0); soffset += stabstrlist.index; stabstralign = balign(soffset,4); soffset += stabstralign; } return soffset; } static unsigned build_symbol_table(symbol *first, void (*newsym)(char *,elfull,elfull, uint8_t,uint8_t, unsigned)) { symbol *symp; unsigned firstglobal; /* file name symbol, when defined */ if (filename) newsym(filename,0,0,STB_LOCAL,STT_FILE,SHN_ABS); if (!no_symbols) /* symbols with local binding first */ for (symp=first; symp; symp=symp->next) if (*symp->name!='.' && *symp->name!=' ' && !(symp->flags&VASMINTERN)) if (symp->type!=IMPORT && !(symp->flags & (EXPORT|WEAK))) newsym(symp->name,get_sym_value(symp),get_sym_size(symp), STB_LOCAL,get_sym_info(symp),get_sym_index(symp)); firstglobal = symindex; /* now the global and weak symbols */ for (symp=first; symp; symp=symp->next) if (*symp->name != '.' && !(symp->flags&VASMINTERN)) if ((symp->type!=IMPORT && (symp->flags & (EXPORT|WEAK))) || (symp->type==IMPORT && (symp->flags & (COMMON|WEAK)))) newsym(symp->name,get_sym_value(symp),get_sym_size(symp), (symp->flags & WEAK) ? STB_WEAK : STB_GLOBAL, get_sym_info(symp),get_sym_index(symp)); return firstglobal; } static void make_reloc_sections(section *sec, void (*newsym)(char *,elfull,elfull, uint8_t,uint8_t, unsigned), void (*addrel)(elfull,elfull,elfull,elfull), void *(*makeshdr)(elfull,elfull,elfull,elfull, elfull,elfull,elfull,elfull)) { struct stabdef *nlist = first_nlist; utaddr roffset = 0; utaddr basero,pc; section *secp; /* ".rela.xxx" or ".rel.xxx" relocation sections */ for (secp=sec; secp; secp=secp->next) { if (secp->idx) { atom *a; utaddr npc; for (a=secp->first,basero=roffset,pc=0; a; a=a->next) { npc = pcalign(a,pc); if (a->type == DATA) roffset += make_relocs(a->content.db->relocs,npc,newsym,addrel); if (a->type == SPACE) roffset += make_relocs(a->content.sb->relocs,npc,newsym,addrel); pc = npc + atom_size(a,secp,npc); } if (basero != roffset) /* were there any relocations? */ make_relsechdr(secp->name,basero,roffset-basero,secp->idx,makeshdr); } } if (!no_symbols) { /* look for relocations in .stab */ basero = roffset; pc = sizeof(struct nlist32); /* skip compilation unit header */ while (nlist != NULL) { if (nlist->base != NULL) roffset += make_stabreloc(pc,nlist,newsym,addrel); nlist = nlist->next; pc += sizeof(struct nlist32); } /* create .rel(a).stab when needed */ if (basero != roffset) make_relsechdr(stabname,basero,roffset-basero,stabidx,makeshdr); } } static void write_strtab(FILE *f,struct StrTabList *strl) { struct StrTabNode *stn; while (stn = (struct StrTabNode *)remhead(&(strl->l))) fwdata(f,stn->str,strlen(stn->str)+1); } static void write_section_data(FILE *f,section *sec) { struct stabdef *nlist = first_nlist; section *secp; for (secp=sec; secp; secp=secp->next) { if (secp->idx && get_sec_type(secp)!=SHT_NOBITS) { atom *a; utaddr pc=0,npc; for (a=secp->first; a; a=a->next) { npc = fwpcalign(f,a,secp,pc); if (a->type == DATA) { fwdata(f,a->content.db->data,a->content.db->size); } else if (a->type == SPACE) { fwsblock(f,a->content.sb); } pc = npc + atom_size(a,secp,npc); } } } if (!no_symbols && nlist!=NULL) { /* write compilation unit header - precedes nlist entries */ fw32(f,1,be); /* source name is first entry in .stabstr */ fw32(f,stablen,be); fw32(f,stabstrlist.index,be); /* write .stab */ while (nlist != NULL) { struct nlist32 n; setval(be,&n.n_strx,4,nlist->name.idx); n.n_type = nlist->type; n.n_other = nlist->other; setval(be,&n.n_desc,2,nlist->desc); setval(be,&n.n_value,4,nlist->value); fwdata(f,&n,sizeof(struct nlist32)); nlist = nlist->next; } /* write .stabstr and align */ write_strtab(f,&stabstrlist); fwspace(f,stabstralign); } } static void write_ELF64(FILE *f,section *sec,symbol *sym) { struct Elf64_Ehdr header; unsigned firstglobal,align1,align2,i; utaddr soffset=sizeof(struct Elf64_Ehdr); struct Shdr64Node *shn; struct Symbol64Node *elfsym; elfrelsize = RELA ? sizeof(struct Elf64_Rela) : sizeof(struct Elf64_Rel); /* initialize ELF header */ memset(&header,0,sizeof(struct Elf64_Ehdr)); init_ident(header.e_ident,ELFCLASS64); setval(be,header.e_type,2,ET_REL); setval(be,header.e_machine,2,cpu); setval(be,header.e_version,4,EV_CURRENT); setval(be,header.e_ehsize,2,sizeof(struct Elf64_Ehdr)); setval(be,header.e_shentsize,2,sizeof(struct Elf64_Shdr)); init_lists(); addShdr64(); /* first section header is always zero */ addSymbol64(NULL); /* first symbol is empty */ /* make program section headers, symbols and relocations */ soffset = prog_sec_hdrs(sec,soffset,makeShdr64,newSym64); firstglobal = build_symbol_table(sym,newSym64); make_reloc_sections(sec,newSym64,addRel64,makeShdr64); /* ".shstrtab" section header string table */ makeShdr64(shstrtabidx,SHT_STRTAB,0, soffset,shstrlist.index,0,1,0); soffset += shstrlist.index; align1 = balign(soffset,4); soffset += align1; /* set last values in ELF header */ setval(be,header.e_shoff,8,soffset); /* remember offset of Shdr table */ soffset += (shdrindex+2)*sizeof(struct Elf64_Shdr); setval(be,header.e_shstrndx,2,shdrindex-1); setval(be,header.e_shnum,2,shdrindex+2); /* ".symtab" symbol table */ shn = makeShdr64(symtabidx,SHT_SYMTAB,0,soffset, symindex*sizeof(struct Elf64_Sym), firstglobal,8,sizeof(struct Elf64_Sym)); setval(be,shn->s.sh_link,4,shdrindex); /* associated .strtab section */ soffset += symindex * sizeof(struct Elf64_Sym); /* ".strtab" string table */ makeShdr64(strtabidx,SHT_STRTAB,0,soffset,strlist.index,0,1,0); soffset += strlist.index; align2 = balign(soffset,4); soffset += align2; /* offset for first Reloc-entry */ /* write ELF header */ fwdata(f,&header,sizeof(struct Elf64_Ehdr)); /* write initialized section contents */ write_section_data(f,sec); /* write .shstrtab string table */ write_strtab(f,&shstrlist); /* write section headers */ fwspace(f,align1); i = 0; while (shn = (struct Shdr64Node *)remhead(&shdrlist)) { if (readval(be,shn->s.sh_type,4) == shtreloc) { /* set correct offset and link to symtab */ setval(be,shn->s.sh_offset,8,readval(be,shn->s.sh_offset,8)+soffset); setval(be,shn->s.sh_link,4,shdrindex-2); /* index of associated symtab */ } fwdata(f,&(shn->s),sizeof(struct Elf64_Shdr)); i++; } /* write symbol table */ while (elfsym = (struct Symbol64Node *)remhead(&symlist)) fwdata(f,&(elfsym->s),sizeof(struct Elf64_Sym)); /* write .strtab string table */ write_strtab(f,&strlist); /* write relocations */ fwspace(f,align2); if (RELA) { struct Rela64Node *rn; while (rn = (struct Rela64Node *)remhead(&relalist)) fwdata(f,&(rn->r),sizeof(struct Elf64_Rela)); } else { struct Rel64Node *rn; while (rn = (struct Rel64Node *)remhead(&relalist)) fwdata(f,&(rn->r),sizeof(struct Elf64_Rel)); } } static void write_ELF32(FILE *f,section *sec,symbol *sym) { struct Elf32_Ehdr header; unsigned firstglobal,align1,align2,i; utaddr soffset=sizeof(struct Elf32_Ehdr); struct Shdr32Node *shn; struct Symbol32Node *elfsym; elfrelsize = RELA ? sizeof(struct Elf32_Rela) : sizeof(struct Elf32_Rel); /* initialize ELF header */ memset(&header,0,sizeof(struct Elf32_Ehdr)); init_ident(header.e_ident,ELFCLASS32); setval(be,header.e_type,2,ET_REL); setval(be,header.e_machine,2,cpu); setval(be,header.e_version,4,EV_CURRENT); #ifdef VASM_CPU_ARM setval(be,header.e_flags,4,0x04000000); /* EABI version 4 */ #endif setval(be,header.e_ehsize,2,sizeof(struct Elf32_Ehdr)); setval(be,header.e_shentsize,2,sizeof(struct Elf32_Shdr)); init_lists(); addShdr32(); /* first section header is always zero */ addSymbol32(NULL); /* first symbol is empty */ /* make program section headers, symbols and relocations */ soffset = prog_sec_hdrs(sec,soffset,makeShdr32,newSym32); firstglobal = build_symbol_table(sym,newSym32); make_reloc_sections(sec,newSym32,addRel32,makeShdr32); /* ".shstrtab" section header string table */ makeShdr32(shstrtabidx,SHT_STRTAB,0, soffset,shstrlist.index,0,1,0); soffset += shstrlist.index; align1 = balign(soffset,4); soffset += align1; /* set last values in ELF header */ setval(be,header.e_shoff,4,soffset); /* remember offset of Shdr table */ soffset += (shdrindex+2)*sizeof(struct Elf32_Shdr); setval(be,header.e_shstrndx,2,shdrindex-1); setval(be,header.e_shnum,2,shdrindex+2); /* ".symtab" symbol table */ shn = makeShdr32(symtabidx,SHT_SYMTAB,0,soffset, symindex*sizeof(struct Elf32_Sym), firstglobal,4,sizeof(struct Elf32_Sym)); setval(be,shn->s.sh_link,4,shdrindex); /* associated .strtab section */ soffset += symindex * sizeof(struct Elf32_Sym); /* ".strtab" string table */ makeShdr32(strtabidx,SHT_STRTAB,0,soffset,strlist.index,0,1,0); soffset += strlist.index; align2 = balign(soffset,4); soffset += align2; /* offset for first Reloc-entry */ /* write ELF header */ fwdata(f,&header,sizeof(struct Elf32_Ehdr)); /* write initialized section contents */ write_section_data(f,sec); /* write .shstrtab string table */ write_strtab(f,&shstrlist); /* write section headers */ fwspace(f,align1); i = 0; while (shn = (struct Shdr32Node *)remhead(&shdrlist)) { if (readval(be,shn->s.sh_type,4) == shtreloc) { /* set correct offset and link to symtab */ setval(be,shn->s.sh_offset,4,readval(be,shn->s.sh_offset,4)+soffset); setval(be,shn->s.sh_link,4,shdrindex-2); /* index of associated symtab */ } fwdata(f,&(shn->s),sizeof(struct Elf32_Shdr)); i++; } /* write symbol table */ while (elfsym = (struct Symbol32Node *)remhead(&symlist)) fwdata(f,&(elfsym->s),sizeof(struct Elf32_Sym)); /* write .strtab string table */ write_strtab(f,&strlist); /* write relocations */ fwspace(f,align2); if (RELA) { struct Rela32Node *rn; while (rn = (struct Rela32Node *)remhead(&relalist)) fwdata(f,&(rn->r),sizeof(struct Elf32_Rela)); } else { struct Rel32Node *rn; while (rn = (struct Rel32Node *)remhead(&relalist)) fwdata(f,&(rn->r),sizeof(struct Elf32_Rel)); } } static void write_output(FILE *f,section *sec,symbol *sym) { cpu = ELFCPU; /* cpu ID */ be = BIGENDIAN; /* true for big endian */ bits = bytespertaddr * bitsperbyte; shtreloc = RELA ? SHT_RELA : SHT_REL; if (bits==32 && cpu!=EM_NONE) write_ELF32(f,sec,sym); else if (bits==64 && cpu!=EM_NONE) write_ELF64(f,sec,sym); else output_error(1,cpuname); /* output module doesn't support cpu */ if (debug && elfsymhash->collisions) printf("*** %d ELF symbol collisions!\n",elfsymhash->collisions); } static int output_args(char *p) { if (!strcmp(p,"-keepempty")) { keep_empty_sects = 1; return 1; } return 0; } int init_output_elf(char **cp,void (**wo)(FILE *,section *,symbol *), int (**oa)(char *)) { *cp = copyright; *wo = write_output; *oa = output_args; return 1; } #else int init_output_elf(char **cp,void (**wo)(FILE *,section *,symbol *), int (**oa)(char *)) { return 0; } #endif