home *** CD-ROM | disk | FTP | other *** search
- /* $VER: pasm output_ehf.c V0.7 (02.01.98)
- *
- * This file is part of pasm, a portable PowerPC assembler.
- * Copyright (c) 1997-98 Frank Wille
- *
- * pasm is freeware and part of the portable and retargetable ANSI C
- * compiler vbcc, copyright (c) 1995-98 by Volker Barthelmann.
- * pasm may be freely redistributed as long as no modifications are
- * made and nothing is charged for it. Non-commercial usage is allowed
- * without any restrictions.
- * EVERY PRODUCT OR PROGRAM DERIVED DIRECTLY FROM MY SOURCE MAY NOT BE
- * SOLD COMMERCIALLY WITHOUT PERMISSION FROM THE AUTHOR.
- *
- *
- * v0.7 (02.01.98) phx
- * Sections after a section with HUNK_EXT were 4 bytes too large.
- * Output format OFMT_ADOS support. The difference between ADOS and
- * and EHF is, that ADOS uses HUNK_CODE instead HUNK_PPC_CODE and
- * doesn't support any PPC-specific relocations and references types.
- * This makes it possible to link simple PowerPC programs with an
- * old linker, like BLink, SLink or PhxLnk.
- * v0.4 (02.07.97) phx
- * File created.
- */
-
-
- #define OUTPUT_EHF_C
- #include "ppcasm.h"
- #include "ehf.h"
-
-
- struct XRefNode {
- struct node n;
- char *sym_name;
- uint8 ref_type;
- int noffsets;
- struct list xreflist;
- };
-
-
- static char *output_name;
- static int nsecs = 0;
- static bool exthunk;
-
-
- void output_ehf(struct GlobalVars *);
-
- static void reloc_hunk(FILE *,struct Section *,uint8,uint32);
- static void unsupp_relocs(struct Section *);
- static void ext_header(FILE *);
- static void ext_refs(FILE *,struct GlobalVars *,struct Section *);
- static void ext_defs(FILE *,struct GlobalVars *,uint32,uint8,uint32);
- static uint32 word_strlen(char *);
- static void write_name(FILE *,struct GlobalVars *,char *);
- static void fwalign(FILE *,struct GlobalVars *,uint32);
- static void fw(FILE *,void *,size_t);
- static void fw4(FILE *,uint32);
-
-
-
- void output_ehf(struct GlobalVars *gv)
- {
- struct Section *nextsec,*sec=(struct Section *)gv->sectionlist.first;
- struct Symbol *symchain;
- uint32 index;
- bool ehfmode = gv->output==OFMT_EHF;
- FILE *fp;
-
- /* assign an index to each valid section */
- while (nextsec = (struct Section *)sec->n.next) {
- if (!(sec->flags & SF_DISCARD) && sec->size > 0)
- sec->index = nsecs++;
- sec = nextsec;
- }
-
- /* create output file */
- output_name = gv->dest_name;
-
- if (fp = fopen(output_name,"w")) { /* create output file */
- fw4(fp,HUNK_UNIT);
- if (gv->ident) {
- fw4(fp,word_strlen(gv->ident)); /* unit name */
- write_name(fp,gv,gv->ident);
- }
- else
- fw4(fp,0);
-
-
- /* section loop */
- sec = (struct Section *)gv->sectionlist.first;
- while (nextsec = (struct Section *)sec->n.next) {
- exthunk = FALSE;
- if (!(sec->flags & SF_DISCARD) && sec->size > 0) {
- index = sec->index;
-
- /* section name */
- fw4(fp,HUNK_NAME);
- fw4(fp,word_strlen(sec->name));
- write_name(fp,gv,sec->name);
-
- /* section type and size */
- switch(sec->type) {
- case ST_CODE:
- ehfmode ? fw4(fp,HUNK_PPC_CODE) : fw4(fp,HUNK_CODE);
- break;
- case ST_DATA:
- fw4(fp,HUNK_DATA);
- break;
- case ST_UDATA:
- fw4(fp,HUNK_BSS);
- break;
- default: /* section type not supported in EHF/ADOS */
- error(52,sec->name,(int)sec->type);
- fw4(fp,HUNK_DATA); /* defaults to HUNK_DATA */
- break;
- }
- fw4(fp,(uint32)(sec->size+3)>>2);
-
- /* write section contents */
- if (!(sec->flags & SF_UNINITIALIZED)) {
- fw(fp,sec->contents,(uint32)sec->size);
- fwalign(fp,gv,(uint32)sec->size);
- }
-
- /* relocation hunks */
- reloc_hunk(fp,sec,R_PPC_ADDR32,HUNK_ABSRELOC32);
- /* @@@ reloc_hunk(fp,sec,R_PPC_ADDR16,HUNK_ABSRELOC16); */
- if (ehfmode)
- reloc_hunk(fp,sec,R_PPC_REL24,HUNK_RELRELOC26);
- reloc_hunk(fp,sec,R_PPC_REL14,HUNK_RELRELOC16);
- reloc_hunk(fp,sec,R_PPC_REL14_BRTAKEN,HUNK_RELRELOC16);
- reloc_hunk(fp,sec,R_PPC_REL14_BRNTAKEN,HUNK_RELRELOC16);
- reloc_hunk(fp,sec,R_PPC_REL32,HUNK_RELRELOC32);
- reloc_hunk(fp,sec,R_PPC_TOC16,HUNK_DREL16);
- unsupp_relocs(sec); /* print unsupported relocations */
-
- /* external references and global definitions */
- ext_refs(fp,gv,sec);
- ext_defs(fp,gv,index,SYM_RELOC,EXT_DEF);
- if (index == 0) /* put absolute definitions in first HUNK_EXT */
- ext_defs(fp,gv,0xffff,SYM_ABS,EXT_ABS);
- if (exthunk)
- fw4(fp,0); /* close HUNK_EXT block */
-
- /* symbol table */
- ext_defs(fp,gv,index,SYM_RELOC,EXT_SYMB);
-
- fw4(fp,HUNK_END); /* end of this hunk */
- }
- sec = nextsec;
- }
-
- fclose(fp);
- }
- else
- error(25,output_name); /* unable to create output file */
- }
-
-
- static void reloc_hunk(FILE *fp,struct Section *sec,uint8 r,uint32 ehfrel)
- /* generate an EHF relocation hunk for a specific reloc type */
- {
- struct Reloc *nextrel,*rel=(struct Reloc *)sec->reloclist.first;
- struct list **rlist=alloc(nsecs*sizeof(struct list *));
- int *rcnt=alloczero(nsecs*sizeof(int)); /* reloc cnt for all sections */
- bool hunk_required=FALSE;
- int i;
-
- for (i=0; i<nsecs; i++) { /* empty reloc lists for each section */
- rlist[i] = alloc(sizeof(struct list));
- initlist(rlist[i]);
- }
-
- while (nextrel = (struct Reloc *)rel->n.next) {
- if (rel->type == r) {
- /* move reloc node of correct type into relocssect's rlist */
- remnode(&rel->n);
- addtail(rlist[rel->relocsect->index],&rel->n);
- rcnt[rel->relocsect->index]++;
- hunk_required = TRUE;
- }
- rel = nextrel;
- }
-
- if (hunk_required) { /* there's at least one relocation */
- fw4(fp,ehfrel); /* reloc hunk id */
- for (i=0; i<nsecs; i++) {
- if (rcnt[i]) {
- fw4(fp,(uint32)rcnt[i]); /* number of relocations */
- fw4(fp,(uint32)i); /* section index */
-
- /* store relocation offsets */
- while(rel = (struct Reloc *)remhead(rlist[i])) {
- fw4(fp,(uint32)rel->offset);
- free(rel);
- }
- }
- }
- fw4(fp,0); /* no more relocation entries */
- }
-
- /* free dynamically allocated rlists and rcnt array */
- for (i=0; i<nsecs; free(rlist[i++]));
- free(rcnt);
- }
-
-
- static void unsupp_relocs(struct Section *sec)
- {
- struct Reloc *nextrel,*rel=(struct Reloc *)sec->reloclist.first;
-
- while (nextrel = (struct Reloc *)rel->n.next) {
- error(53,elfrel_name[rel->type & ELFRELNAMMSK],rel->offset,sec->name);
- rel = nextrel;
- }
- }
-
-
- static void ext_header(FILE *fp)
- {
- if (!exthunk) {
- exthunk = TRUE;
- fw4(fp,HUNK_EXT);
- }
- }
-
-
- static void ext_refs(FILE *fp,struct GlobalVars *gv,struct Section *sec)
- {
- struct list xnodelist; /* xrefs with same ref. type and symbol name */
- struct XRefNode *xn,*nextxn;
- struct XReference *xref;
-
- initlist(&xnodelist);
- while (xref = (struct XReference *)remhead(&sec->xreflist)) {
- char *name = xref->xsymbol->name; /* name of xref'ed symbol */
- uint8 rtype = xref->type;
-
- /* ELF32 -> EHF reference type mapping */
- switch (rtype) {
- case R_PPC_ADDR32:
- rtype = EXT_ABSREF32;
- break;
- case R_PPC_REL14:
- case R_PPC_REL14_BRTAKEN:
- case R_PPC_REL14_BRNTAKEN:
- case R_PPC_ADDR16:
- rtype = EXT_RELREF16;
- break;
- case R_PPC_TOC16:
- rtype = EXT_DEXT16; /* small data */
- break;
- case R_PPC_REL24:
- if (gv->output == OFMT_EHF) {
- rtype = EXT_RELREF26;
- break;
- }
- default:
- error(53,elfrel_name[rtype & ELFRELNAMMSK],xref->offset,sec->name);
- rtype = EXT_RELREF8; /* @@@ to keep the loop running */
- break;
- }
-
- /* search appropriate XRefNode for referenced symbol and type */
- xn = (struct XRefNode *)xnodelist.first;
- while (nextxn = (struct XRefNode *)xn->n.next) {
- if (!strcmp(name,xn->sym_name) && rtype==xn->ref_type)
- break;
- xn = nextxn;
- }
-
- if (nextxn==NULL) { /* we have to create a new XRefNode? */
- xn = alloc(sizeof(struct XRefNode));
- xn->sym_name = name;
- xn->ref_type = rtype;
- xn->noffsets = 0;
- initlist(&xn->xreflist);
- addtail(&xnodelist,&xn->n);
- }
-
- /* add new offset to xreflist for same ref. type and symbol name */
- addtail(&xn->xreflist,&xref->n);
- xn->noffsets++;
- }
-
- if (xnodelist.first->next) { /* at least one reference in this section? */
- ext_header(fp);
- while (xn = (struct XRefNode *)remhead(&xnodelist)) {
- fw4(fp,((uint32)xn->ref_type << 24) | word_strlen(xn->sym_name));
- write_name(fp,gv,xn->sym_name); /* symbol's name */
- fw4(fp,(uint32)xn->noffsets); /* number of references */
- while (xref = (struct XReference *)remhead(&xn->xreflist)) {
- fw4(fp,(uint32)xref->offset); /* offset */
- free(xref);
- }
- free(xn);
- }
- }
- }
-
-
- static void ext_defs(FILE *fp,struct GlobalVars *gv,uint32 idx,
- uint8 stype,uint32 xdeftype)
- {
- struct Symbol *sym;
- bool xdefs = FALSE;
- int i;
-
- for (i=0; i<SYMHTABSIZE; i++) {
- sym = gv->symbols[i];
- while (sym) {
- if (sym->type==stype &&
- (sym->info==SYMI_NOTYPE || sym->info==SYMI_FUNC)) {
- if (idx == ((stype==SYM_RELOC) ? sym->relsect->index : 0xffff)) {
- if (sym->bind > SYMB_LOCAL) {
- if (!xdefs) {
- xdefs = TRUE;
- if (xdeftype == EXT_SYMB)
- fw4(fp,HUNK_SYMBOL);
- else
- ext_header(fp);
- }
-
- /* generate xdef oder symbol table entry */
- fw4(fp,(xdeftype << 24) | word_strlen(sym->name));
- write_name(fp,gv,sym->name); /* symbol's name */
- fw4(fp,sym->value); /* ... and its value */
- }
- }
- }
- sym = sym->hash_chain;
- }
- }
- if (xdefs && xdeftype==EXT_SYMB)
- fw4(fp,0); /* end of symbol table for this hunk */
- }
-
-
- static uint32 word_strlen(char *s)
- /* calculate number of 32 bit words required for
- a string without terminator */
- {
- uint32 l;
-
- if (l = (uint32)strlen(s))
- l = (l+3)>>2;
- return (l);
- }
-
-
- static void write_name(FILE *fp,struct GlobalVars *gv,char *name)
- /* write a unit/section/symbol name word-aligned */
- {
- size_t nl=strlen(name);
-
- fw(fp,name,nl);
- fwalign(fp,gv,(uint32)nl);
- }
-
-
- static void fwalign(FILE *fp,struct GlobalVars *gv,uint32 n)
- {
- fw(fp,gv->alignment_bytes,(4-(n&3))&3);
- }
-
-
- static void fw(FILE *fp,void *buf,size_t len)
- {
- if (len) {
- if (!fwrite(buf,1,len,fp)) {
- fclose(fp);
- error(26,output_name); /* write error */
- }
- }
- }
-
-
- static void fw4(FILE *fp,uint32 w)
- /* write a 32 bit word, automatic endian conversion */
- {
- w = ECVW(w);
- if (!fwrite(&w,1,sizeof(uint32),fp)) {
- fclose(fp);
- error(26,output_name); /* write error */
- }
- }
-