Skip to content
Find file
Fetching contributors…
Cannot retrieve contributors at this time
345 lines (279 sloc) 9.31 KB
/* $VER: vlink t_ataritos.c V0.13 (02.11.10)
*
* This file is part of vlink, a portable linker for multiple
* object formats.
* Copyright (c) 1997-2010 Frank Wille
*
* vlink is freeware and part of the portable and retargetable ANSI C
* compiler vbcc, copyright (c) 1995-2010 by Volker Barthelmann.
* vlink 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.
*/
#include "config.h"
#ifdef ATARI_TOS
#define T_ATARITOS_C
#include "vlink.h"
#include "tosdefs.h"
static int identify(char *,uint8_t *,unsigned long,bool);
static void readconv(struct GlobalVars *,struct LinkFile *);
static int targetlink(struct GlobalVars *,struct LinkedSection *,
struct Section *);
static unsigned long headersize(struct GlobalVars *);
static void writeobject(struct GlobalVars *,FILE *);
static void writeshared(struct GlobalVars *,FILE *);
static void writeexec(struct GlobalVars *,FILE *);
struct FFFuncs fff_ataritos = {
"ataritos",
defaultscript,
NULL,
headersize,
identify,
readconv,
NULL,
targetlink,
NULL,
NULL,
NULL,
NULL,NULL,NULL,
writeobject,
writeshared,
writeexec,
bss_name,NULL,
0,
0x7ffe,
0,
0,
RTAB_STANDARD,RTAB_STANDARD,
_BIG_ENDIAN_,
32,
FFF_BASEINCR
};
/*****************************************************************/
/* Read Atari TOS */
/*****************************************************************/
static int identify(char *name,uint8_t *p,unsigned long plen,bool lib)
/* identify a TOS file */
{
return ID_UNKNOWN; /* @@@ no read-support at the moment */
}
static void readconv(struct GlobalVars *gv,struct LinkFile *lf)
{
ierror("readconv(): Can't read Atari TOS");
}
/*****************************************************************/
/* Link Atari TOS */
/*****************************************************************/
static int targetlink(struct GlobalVars *gv,struct LinkedSection *ls,
struct Section *s)
/* returns 1, if target requires the combination of the two sections, */
/* returns -1, if target doesn't want to combine them, */
/* returns 0, if target doesn't care - standard linking rules are used. */
{
/* TOS requires that all sections of type CODE or DATA or BSS */
/* will be combined, because there are only those three available! */
if (ls->type == s->type)
return 1;
return 0;
}
/*****************************************************************/
/* Write Atari TOS */
/*****************************************************************/
static int tos_initwrite(struct GlobalVars *gv,
struct LinkedSection **sections)
/* find exactly one ST_CODE, ST_DATA and ST_UDATA section, which
will become .text, .data and .bss,
then count the number of symbol definitions and references */
{
static const char *fn = "tos_initwrite(): ";
struct LinkedSection *ls;
struct Symbol *sym;
struct Reloc *xref;
int i,cnt;
get_text_data_bss(gv,sections);
/* count symbols and unresolved references */
for (i=0,cnt=0; i<3; i++) {
if (sections[i]) {
for (sym=(struct Symbol *)sections[i]->symbols.first;
sym->n.next!=NULL; sym=(struct Symbol *)sym->n.next) {
if (!discard_symbol(gv,sym)) {
++cnt;
if (strlen(sym->name) > DRI_NAMELEN)
++cnt; /* extra symbol for long name */
}
}
if (gv->dest_object) {
for (xref=(struct Reloc *)sections[i]->xrefs.first;
xref->n.next!=NULL; xref=(struct Reloc *)xref->n.next) {
++cnt;
if (strlen(xref->xrefname) > DRI_NAMELEN)
++cnt; /* extra symbol for long name */
}
}
}
}
text_data_bss_gaps(sections); /* calculate gap size between sections */
return cnt;
}
static void tos_header(FILE *f,unsigned long tsize,unsigned long dsize,
unsigned long bsize,unsigned long ssize,
unsigned long flags)
{
PH hdr;
write16be(hdr.ph_branch,0x601a);
write32be(hdr.ph_tlen,tsize);
write32be(hdr.ph_dlen,dsize);
write32be(hdr.ph_blen,bsize);
write32be(hdr.ph_slen,ssize);
write32be(hdr.ph_magic,0);
write32be(hdr.ph_flags,flags);
write16be(hdr.ph_abs,0);
fwritex(f,&hdr,sizeof(PH));
}
static void write_dri_sym(FILE *f,const char *name,
uint16_t type,uint32_t value)
{
struct DRIsym stab;
int longname = strlen(name) > DRI_NAMELEN;
strncpy(stab.name,name,DRI_NAMELEN);
write16be(stab.type,longname?(type|STYP_LONGNAME):type);
write32be(stab.value,value);
fwritex(f,&stab,sizeof(struct DRIsym));
if (longname) {
char rest_of_name[sizeof(struct DRIsym)];
memset(rest_of_name,0,sizeof(struct DRIsym));
strncpy(rest_of_name,name+DRI_NAMELEN,sizeof(struct DRIsym));
fwritex(f,rest_of_name,sizeof(struct DRIsym));
}
}
static void tos_symboltable(struct GlobalVars *gv,FILE *f,
struct LinkedSection **sections)
{
struct Symbol *sym;
struct Reloc *xref;
int i;
for (i=0; i<3; i++) {
if (sections[i]) {
for (sym=(struct Symbol *)sections[i]->symbols.first;
sym->n.next!=NULL; sym=(struct Symbol *)sym->n.next) {
if (!discard_symbol(gv,sym)) {
uint16_t t;
if (sym->type == SYM_ABS) {
t = STYP_EQUATED; /* @@@ correct? */
}
else if (sym->type != SYM_COMMON) {
switch (i) {
case 0: t = STYP_TEXT; break;
case 1: t = STYP_DATA; break;
case 2: t = STYP_BSS; break;
}
}
else
ierror("tos_symboltable(): Common symbol <%s> not supported",
sym->name);
t |= STYP_DEFINED;
if (sym->bind > SYMB_LOCAL)
t |= STYP_GLOBAL;
write_dri_sym(f,sym->name,t,sym->value);
}
}
if (gv->dest_object) {
/* @@@ test - objects are not really supported for now... */
for (xref=(struct Reloc *)sections[i]->xrefs.first;
xref->n.next!=NULL; xref=(struct Reloc *)xref->n.next) {
/* @@@ no idea if this is correct - what about ref.type??? */
write_dri_sym(f,xref->xrefname,STYP_EXTERNAL,
sections[i]->base + xref->offset);
}
}
}
}
}
void tos_writerelocs(struct GlobalVars *gv,FILE *f,
struct LinkedSection **sections)
{
const char *fn = "tos_writerelocs(): ";
int i;
struct Reloc *rel;
struct RelocInsert *ri;
unsigned long lastoffs = 0;
for (i=0; i<3; i++) {
if (sections[i]) {
sort_relocs(&sections[i]->relocs);
for (rel=(struct Reloc *)sections[i]->relocs.first;
rel->n.next!=NULL; rel=(struct Reloc *)rel->n.next) {
if (ri = rel->insert) {
if (rel->rtype!=R_ABS || ri->bpos!=0 || ri->bsiz!=32) {
error(32,fff_ataritos.tname,reloc_name[rel->rtype],
(int)ri->bpos,(int)ri->bsiz,ri->mask,
sections[i]->name,rel->offset);
continue;
}
}
else
continue;
if (!lastoffs) {
/* first relocation offset is 32 bits, the rest are bytes! */
fwrite32be(f,sections[i]->base + rel->offset);
}
else {
long diff = (sections[i]->base + rel->offset) - lastoffs;
if (diff < 0) {
ierror("%snegative offset difference: "
"%s(0x%08lx)+0x%08lx - 0x%08lx",fn,sections[i]->name,
sections[i]->base,rel->offset,lastoffs);
}
while (diff > 254) {
fwrite8(f,1);
diff -= 254;
}
fwrite8(f,(uint8_t)diff);
}
lastoffs = sections[i]->base + rel->offset;
}
}
}
if (!lastoffs) {
/* not a single relocation written - write 0-word */
fwrite32be(f,0);
}
else
fwrite8(f,0);
}
static unsigned long headersize(struct GlobalVars *gv)
{
return 0; /* irrelevant */
}
static void writeshared(struct GlobalVars *gv,FILE *f)
{
error(30); /* Target file format doesn't support shared objects */
}
static void writeobject(struct GlobalVars *gv,FILE *f)
/* creates a TOS relocatable object file */
{
ierror("Atari TOS object file generation has not yet been implemented");
}
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]->filesize : 0,
(sections[2] ? sections[2]->size : 0) +
(sections[1] ? sections[1]->gapsize : 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]->size+sections[0]->gapsize);
if (sections[1])
fwritex(f,sections[1]->data,sections[1]->filesize);
if (nsyms)
tos_symboltable(gv,f,sections);
tos_writerelocs(gv,f,sections);
}
#endif
Something went wrong with that request. Please try again.