static void writeexec(struct GlobalVars *gv,FILE *f) /* creates a TOS executable file (which is relocatable) */ { struct LinkedSection *sections[3]; int nsyms = tos_initwrite(gv,sections); int i; tos_header(f,sections[0] ? sections[0]->size+sections[0]->gapsize : 0, sections[1] ? sections[1]->size+sections[1]->gapsize : 0, sections[2] ? sections[2]->size : 0, (unsigned long)nsyms*sizeof(struct DRIsym),gv->tosflags); for (i=0; i<3; i++) calc_relocs(gv,sections[i]); if (sections[0]) { fwritex(f,sections[0]->data,sections[0]->filesize); fwritegap(f,(sections[0]->size-sections[0]->filesize)+sections[0]->gapsize); } if (sections[1]) { fwritex(f,sections[1]->data,sections[1]->filesize); fwritegap(f,(sections[1]->size-sections[1]->filesize)+sections[1]->gapsize); } if (nsyms) tos_symboltable(gv,f,sections); tos_writerelocs(gv,f,sections); }
static void rawseg_writeexec(struct GlobalVars *gv,FILE *f) /* creates a new file for each segment, writes file name, start address */ /* and length into the output file */ { const char *fn = "rawseg_writeexec(): "; bool firstsec; unsigned long addr; FILE *segf; struct Phdr *p; struct LinkedSection *ls,*prevls; struct SegReloc *srlist; char buf[256]; for (p=gv->phdrlist; p; p=p->next) { if (p->type==PT_LOAD && (p->flags&PHDR_USED) && p->start!=ADDR_NONE && p->start_vma!=ADDR_NONE) { firstsec = TRUE; srlist = NULL; snprintf(buf,256,"%s.%s",gv->dest_name,p->name); segf = fopen(buf,"wb"); if (segf == NULL) { error(29,buf); /* cannot create file */ continue; } /* write file name, start address and length of segment to output */ fprintf(f,"\"%s\" 0x%llx 0x%llx\n",buf,p->start,p->mem_end-p->start); /* write segment's sections */ for (ls=(struct LinkedSection *)gv->lnksec.first; ls->n.next!=NULL; ls=(struct LinkedSection *)ls->n.next) { if (ls->copybase>=(unsigned long)p->start && (ls->copybase+ls->size)<=(unsigned long)p->mem_end && (ls->flags & SF_ALLOC)) { if (gv->keep_relocs) { /* remember relocations, adjusted from section to segment base */ struct Reloc *r; struct RelocInsert *ri; struct LinkedSection *relsec; struct Phdr *relph; for (r=(struct Reloc *)ls->relocs.first; r->n.next!=NULL; r=(struct Reloc *)r->n.next) { if (ri = r->insert) { if (r->rtype!=R_ABS || ri->bpos!=0 || ri->bsiz!=32) { /* only absolute 32-bit relocs are supported */ error(32,fff_rawseg.tname,reloc_name[r->rtype], (int)ri->bpos,(int)ri->bsiz,ri->mask, ls->name,r->offset); continue; } } else continue; if (r->relocsect.lnk == NULL) { if (r->flags & RELF_DYNLINK) continue; /* NULL, because it was resolved by a sh.obj. */ else ierror("%sReloc type %d (%s) at %s+0x%lx " "(addend 0x%llx) is missing a relocsect.lnk", fn,(int)r->rtype,reloc_name[r->rtype],ls->name, r->offset,r->addend); } relsec = r->relocsect.lnk; /* find out to which segment relsec belongs */ for (relph=gv->phdrlist; relph; relph=relph->next) { if (relph->type==PT_LOAD && (relph->flags&PHDR_USED) && relph->start!=ADDR_NONE && relph->start_vma!=ADDR_NONE) { if (relsec->copybase>=(unsigned long)relph->start && (relsec->copybase+relsec->size)<= (unsigned long)relph->mem_end && (relsec->flags & SF_ALLOC)) break; } } /* use segment's base address for relocation instead */ if (relph) { lword segoffs,a,v; struct SegReloc *newsr,*srp; segoffs = (lword)relsec->copybase - relph->start; v = writesection(gv,ls->data+r->offset,r,r->addend+segoffs); if (v != 0) { /* Calculated value doesn't fit into relocation type x ... */ if (ri = r->insert) error(35,gv->dest_name,ls->name,r->offset,v, reloc_name[r->rtype],(int)ri->bpos, (int)ri->bsiz,ri->mask); else ierror("%sReloc (%s+%lx), type=%s, without RelocInsert", fn,ls->name,r->offset,reloc_name[r->rtype]); } /* remember relocation offset and segment for later */ newsr = alloc(sizeof(struct SegReloc)); newsr->next = NULL; newsr->seg = relph; newsr->offset = (ls->copybase - (unsigned long)p->start) + r->offset; if (srp = srlist) { while (srp->next) srp = srp->next; srp->next = newsr; } else srlist = newsr; } else ierror("%sNo segment for reloc offset section '%s'", fn,relsec->name); } } else calc_relocs(gv,ls); if (!firstsec) { /* write an alignment gap, when needed */ if (ls->copybase > addr) fwritegap(segf,ls->copybase-addr); else if (ls->copybase < addr) error(98,fff[gv->dest_format]->tname,ls->name,prevls->name); } else firstsec = FALSE; fwritex(segf,ls->data,ls->size); addr = ls->copybase + ls->size; prevls = ls; } } fclose(segf); if (srlist) { /* write relocation files for this segment */ struct Phdr *relph; struct SegReloc *sr; uint32_t rcnt; FILE *rf; for (relph=gv->phdrlist; relph; relph=relph->next) { for (sr=srlist,rf=NULL,rcnt=0; sr; sr=sr->next) { if (sr->seg == relph) { if (!rf) { snprintf(buf,256,"%s.%s.rel%s", gv->dest_name,p->name,relph->name); rf = fopen(buf,"wb"); if (rf == NULL) { error(29,buf); /* cannot create file */ continue; } fwritegap(rf,4); /* number of relocs will be stored here */ } if (gv->endianess == _BIG_ENDIAN_) fwrite32be(rf,sr->offset); else fwrite32le(rf,sr->offset); rcnt++; } } if (rf) { /* write number of relocs into the first word */ fseek(rf,0,SEEK_SET); if (gv->endianess == _BIG_ENDIAN_) fwrite32be(rf,rcnt); else fwrite32le(rf,rcnt); fclose(rf); } } } } } }
static void aoutmint_writeexec(struct GlobalVars *gv,FILE *f) /* creates an a.out-MiNT executable file */ { const int be = _BIG_ENDIAN_; uint8_t jmp_entry_code[] = { 0x20,0x3a,0x00,0x1a,0x4e,0xfb,0x08,0xfa }; struct LinkedSection *sections[3]; unsigned long secsizes[2]; struct mint_exec me; long tparel_offset,tparel_size; struct nlist32 *stksize; aout_initwrite(gv,sections); if (sections[0] == NULL) /* this requires a .text section! */ error(97,fff[gv->dest_format]->tname,TEXTNAME); memset(&me,0,sizeof(struct mint_exec)); /* init header with zero */ text_data_bss_gaps(sections); /* calculate gap size between sections */ secsizes[0] = sections[0]->size + sections[0]->gapsize; secsizes[1] = sections[1] ? sections[1]->filesize : 0; /* init TOS header */ write16be(me.tos.ph_branch,0x601a); write32be(me.tos.ph_tlen,secsizes[0]+TEXT_OFFSET); write32be(me.tos.ph_dlen,secsizes[1]); write32be(me.tos.ph_blen,(sections[2]?sections[2]->size:0) + (sections[1]?sections[1]->gapsize:0)); write32be(me.tos.ph_magic,0x4d694e54); /* "MiNT" */ write32be(me.tos.ph_flags,gv->tosflags); /* Atari memory flags */ write16be(me.tos.ph_abs,0); /* includes relocations */ aout_addsymlist(gv,sections,BIND_GLOBAL,0,be); aout_addsymlist(gv,sections,BIND_WEAK,0,be); aout_addsymlist(gv,sections,BIND_LOCAL,0,be); aout_debugsyms(gv,be); calc_relocs(gv,sections[0]); calc_relocs(gv,sections[1]); /* The Atari symbol table size is the sum of a.out symbols and strings, which is now known. */ write32be(me.tos.ph_slen,aoutsymlist.nextindex * sizeof(struct nlist32) + aoutstrlist.nextoffset); /* set jmp_entry to move.l a_entry(pc),d0 jmp (-6,pc,d0.l) */ memcpy(me.jmp_entry,jmp_entry_code,sizeof(jmp_entry_code)); /* init a.out NMAGIC header */ SETMIDMAG(&me.aout,NMAGIC,0,0); write32be(me.aout.a_text,sections[0]->size+sections[0]->gapsize); write32be(me.aout.a_data,sections[1]?sections[1]->filesize:0); write32be(me.aout.a_bss,(sections[2]?sections[2]->size:0) + (sections[1]?sections[1]->gapsize:0)); write32be(me.aout.a_syms,aoutsymlist.nextindex*sizeof(struct nlist32)); write32be(me.aout.a_entry,TEXT_OFFSET); /* save offset to __stksize when symbol is present */ if (stksize = find_aout_sym("__stksize")) { write32be(me.stkpos, read32be(&stksize->n_value)+sizeof(me)-TEXT_OFFSET); } /* write a.out-MiNT header (256 bytes) */ fwritex(f,&me,sizeof(me)); /* write sections */ fwritex(f,sections[0]->data,sections[0]->size); fwritegap(f,sections[0]->gapsize); if (sections[1]) fwritex(f,sections[1]->data,sections[1]->filesize); /* write a.out symbols */ aout_writesymbols(f); aout_writestrings(f,be); /* write TPA relocs */ tparel_offset = ftell(f); tos_writerelocs(gv,f,sections); tparel_size = ftell(f) - tparel_offset; /* we have to patch tparel_pos and tparel_size in the header, as we didn't know about the size of the TPA relocs table before */ fseek(f,offsetof(struct mint_exec,tparel_pos),SEEK_SET); fwrite32be(f,tparel_offset); fwrite32be(f,tparel_size); }