/* 6502/10 linker (lld) Version 0.07 Written by Daniel Dallmann (aka Poldi) in Sep 1996. This piece of software is freeware ! So DO NOT sell it !! You may copy and redistribute this file for free, but only with this header unchanged in it. (Or you risc eternity in hell) If you've noticed a bug or created an additional feature, let me know. My (internet) email-address is (dan.da at gmx.de) Feb 18 2000 *poldi* -N : LNG mode operation Jun 9 1999 *poldi* code cleaning Jun 8 *Stefan Haubenthal* AMIGA related patches Nov 1 1998 *poldi* added: "-d file", output readable list of all global labels and their value Jun 21 1997 *poldi* added: environment variable that holds a list of librarys that are included per default. added: flag for quiet operation fixed: duplicated global error message Jun 15 1997 *poldi* fixed: bug in library creation code. Dec 15 1996 *poldi* added support of LUnix-code ... */ #include #include #include #undef debug #define USE_GETENV /* use LLD_LIBRARYS to find librarys */ #ifdef _AMIGA const char *VERsion="$VER: lld 0.07 "__AMIGADATE__" $"; #define PATH_SEPARATOR ',' /* character used as path separator */ #else #define PATH_SEPARATOR ':' /* character used as path separator */ #endif /* export LLD_LIBRARYS=/usr/lib/c64:/usr/lib/lunix ^ ^ dir. separator path separator NOTE: LLD_LIBRARYS used for normal objectfiles LUNA_LIBRARYS used for lunix objectfiles LNG_LIBRARYS used for normal objectfiles in LNG mode */ #define FILES_MAX 50 /* max number of files to link */ #define GLOBALS_MAX 500 /* max number of globals in an objectfile */ #define LABEL_LENGTH_MAX 40 /* max length of label-names */ #define LIB_NUM_MAX 4 /* max number of librarys to link against */ #define MOD_NUM_MAX FILES_MAX /* max number of objects in a library */ #define NOTHING (-1) /* prototypes */ void make_lib(void); void Howto(void); void error(char*); void derror(char*); int search_global(char*); void ill_object(char*); void ill_library(char*); int search_unknown(char*); char *str_sav(char*); void add_global(char*, int); void add_unknown(char*); int read_byte(FILE*, char*); void write_byte(FILE*, unsigned char); void make_code(int, int, char*); FILE *open_ext(char*, unsigned int*); void add_code(FILE*, char*, int); void write_buffer(FILE*); /* global variables */ static char *global[GLOBALS_MAX]; static char *unknown[GLOBALS_MAX]; static int glob_val[GLOBALS_MAX]; static int global_num; static int unknown_num; static int errors; static char str[150]; static char *infile[FILES_MAX]; static int infile_num; static char *file_output; static char *code_buffer; static int code_buffer_ptr; static int code_buffer_length; static int quiet_mode; void remove_unknown(int); void error(char *text) { printf(" error:%s\n",text); errors++; } void derror(char *text) { printf(" panic:%s\n",text); exit(1); } int search_global(char *name) { int i; # ifdef debug printf("# search global \"%s\"\n",name); # endif i=0; while (i=GLOBALS_MAX) { error("too many globals"); exit(1); } i=search_global(name); if (i!=NOTHING) { sprintf(str,"duplicated label \"%s\"",name); error(str); return; } i=search_unknown(name); if (i!=NOTHING) remove_unknown(i); global[global_num]=str_sav(name); glob_val[global_num]=val; global_num++; } void add_unknown(char *name) { int i; # ifdef debug printf("# add unknown \"%s\"\n",name); # endif if (unknown_num>=GLOBALS_MAX) { error("too many globals"); exit(1); } i=search_unknown(name); if (i!=NOTHING) return; unknown[unknown_num]=str_sav(name); unknown_num++; } int read_byte(FILE *stream, char *name) { static int tmp; tmp=fgetc(stream); if (tmp==EOF) { sprintf(str,"unexpected EOF reading \"%s\"",name); error(str); exit(1); } return tmp; } void write_byte(FILE *stream, unsigned char byte) { if (fputc(byte,stream)==EOF) { error("i/o-error while writing to outfile"); exit(1); } } void make_code(int flags, int val, char *fname) { if (code_buffer_ptr+2>=code_buffer_length) printf("%i of %i !\n",code_buffer_ptr,code_buffer_length); /*ill_object(fname);*/ if ((flags&0x03)==0x03) { /* put word */ code_buffer[code_buffer_ptr++]=val & 0xff; code_buffer[code_buffer_ptr++]=(val>>8) & 0xff; } else if (flags&0x01) { /* only put low byte */ code_buffer[code_buffer_ptr++]=val & 0xff; } else if (flags&0x02) { /* only put high byte */ code_buffer[code_buffer_ptr++]=(val>>8)&0xff; } else ill_object(fname); return; } FILE *open_ext(char *file, unsigned int *size) { FILE *inf; inf=fopen(file,"r"); if (inf==NULL) { sprintf(str,"can't open inputfile \"%s\"",file); error(str); exit(1); } read_byte(inf,file); read_byte(inf,file); read_byte(inf,file); /* skip globals */ while (read_byte(inf,file)!=0) { while (read_byte(inf,file)!=0) ; read_byte(inf,file); read_byte(inf,file); } /* skip length of module-code */ *size=read_byte(inf,file)+(read_byte(inf,file)<<8); return inf; } void make_lib() { int f_num; FILE *outf, *inf; char *fname; int tmp; unsigned int size; outf=fopen(file_output,"w"); if (outf==NULL) { error("can't write to output-file"); exit(1); } write_byte(outf,'l'); write_byte(outf,'i'); write_byte(outf,'b'); f_num=0; while (f_num=code_buffer_length) ill_object(fname); while (tmp!=0) { code_buffer[code_buffer_ptr++]=read_byte(inf,fname); tmp--; } } else if ((tmp&0xf0)==0x80) { /* normal relocation */ i=read_byte(inf,fname)|(read_byte(inf,fname)<<8); make_code(tmp,i+pc,fname); } else if ((tmp&0xf0)==0xc0) { /* insert value of external */ i=read_byte(inf,fname)|(read_byte(inf,fname)<<8); if (i<0 || i>map_size) { printf("no. of external out of range\n"); ill_object(fname); } make_code(tmp,glob_val[lab_map[i]],fname); } else if ((tmp&0xf0)==0xd0) { /* insert modified value of external */ i=read_byte(inf,fname)|(read_byte(inf,fname)<<8); j=read_byte(inf,fname)|(read_byte(inf,fname)<<8); if (j&0x8000) j-=0x10000; if (i<0 || i>map_size) { printf("no. of external out of range\n"); ill_object(fname); } make_code(tmp,glob_val[lab_map[i]]+j,fname); } else { printf("prefix %i unknown\n",tmp); ill_object(fname); } } } void write_buffer(FILE *outf) { int i; # ifdef debug printf("writing buffer (%i/%i bytes)\n",code_buffer_ptr,code_buffer_length); # endif i=0; while (i=LIB_NUM_MAX) { error("too many librarys"); exit(1); } lib[lib_num]=argv[i]; lib_num++; j=0; break; } case 's': { i++; if (sscanf(argv[i],"%i",&pc)==0) Howto(); j=0; break; } default: Howto(); } if (i==argc) Howto(); if (j==0) break; j++; } } else { if (infile_num>=FILES_MAX) { error("too many inputfiles"); exit(1); } infile[infile_num]=argv[i]; infile_num++; } i++; } if (infile_num==0) { printf("%s: No input file\n",argv[0]); exit(1); } if (file_output==NULL) if (!lib_flag) file_output="c64.out"; else { file_output="c64.lib"; } if (lib_flag) { if (lib_num!=0) { error("can't create library including librarys"); exit(1); } make_lib(); exit(0); } if (pc>0xffff) { error("illegal address"); exit(1); } if (lng_mode && pc!=0x1000) error("LNG binaries have start address 0x1000"); pc_start=pc; /* first built up database */ f_num=0; while (f_num=LABEL_LENGTH_MAX) { error("label too long"); exit(1); } } tmp=read_byte(inf,fname)+(read_byte(inf,fname)<<8); add_global(tmpname,tmp+pc); } size=read_byte(inf,fname)+(read_byte(inf,fname)<<8); # ifdef debug printf("# size is %i\n",size); # endif /* read list of externals */ while ((tmp=read_byte(inf,fname))!=0) { j=1; tmpname[0]=tmp; while ((tmpname[j]=read_byte(inf,fname))!=0) { j++; if (j>=LABEL_LENGTH_MAX) { error("label too long"); exit(1); } } if (search_global(tmpname)==NOTHING) add_unknown(tmpname); } fclose(inf); pc+=size; if (pc>0xffff) { error("code crossed 64k border"); exit(1); } f_num++; } #ifdef USE_GETENV /* add librays specified by environment variable */ if (lunix_mode) envtmp=getenv("LUNIX_LIBRARYS"); else if (lng_mode) envtmp=getenv("LNG_LIBRARYS"); else envtmp=getenv("LLD_LIBRARYS"); if (envtmp!=NULL) { char *tmp_name; while (1) { i=0; while (envtmp[i]!='\0' && envtmp[i]!=PATH_SEPARATOR) i++; if (lib_num>=LIB_NUM_MAX) { error("too many librarys\n"); exit(1); } tmp_name=(char*)malloc(sizeof(char)*(i+1)); strncpy(tmp_name,envtmp,i); tmp_name[i]='\0'; lib[lib_num++]=tmp_name; if (envtmp[i]!='\0') envtmp=&envtmp[i+1]; else break; } } #endif /* now get symbols from librarys */ f_num=0; while (f_num=LABEL_LENGTH_MAX) { error("label too long"); exit(1); } } tmp=read_byte(inf,fname)+(read_byte(inf,fname)<<8); if(search_unknown(tmpname)!=NOTHING) { need_flag=1; if (mod__flag[mod_cnt]==0) flag=1; if (i==-1) add_global(tmpname,pc+tmp); } else { if (i==-1 && search_global(tmpname)!=NOTHING) { char message[200]; sprintf(message,"duplicated global \"%s\"",tmpname); error(message); }} tmp=read_byte(inf,fname); } tmp=read_byte(inf,fname)+(read_byte(inf,fname)<<8); lib_clen[f_num][mod_cnt]=tmp; if (i==-1 && need_flag) { pc+=tmp; if (pc>0xffff) { error("code crossed 64k border"); exit(1); } } if (flag) { /* okay, we need this module, so add its unknowns ! */ # ifdef debug printf("# need module %i\n",mod_cnt); # endif mod__flag[mod_cnt]=1; solved_flag=1; while ((tmp=read_byte(inf,fname))!=0) { j=1; tmpname[0]=tmp; while ((tmpname[j]=read_byte(inf,fname))!=0) { j++; if (j>=LABEL_LENGTH_MAX) { error("label too long"); exit(1); } } if (search_global(tmpname)==NOTHING) add_unknown(tmpname); } } else { while (read_byte(inf,fname)!=0) while (read_byte(inf,fname)!=0) ; } mod_cnt++; } i++; if (!solved_flag) if (i!=0) { i=-1; solved_flag=1; } } mod_flag[f_num]=mod__flag; lib_size[f_num]=mod_num; f_num++; } /* are there still unresolved labels ? ... */ # ifdef debug printf("\n"); # endif i=0; while (i>8)&0xff); /* put start address */ } } f_num=0; while (f_num>8; code_buffer[2]=1+((pc_end-pc_start-1)>>8); # ifdef debug printf(" lunix base page = %i\n",code_buffer[65]); printf(" lunix code length = %i pages (%i bytes)\n", code_buffer[2],pc_end-pc_start); # endif } if (lng_mode && f_num==0) { /* have to adapt something in the header ! */ code_buffer[5]=pc_start>>8; code_buffer[4]=((pc_end-pc_start+255)>>8); # ifdef debug printf(" lng base page = %i\n",code_buffer[5]); printf(" lng code length = %i pages (%i bytes)\n", code_buffer[4],pc_end-pc_start); # endif } write_buffer(outf); free(code_buffer); fclose(inf); pc+=size; # ifdef debug printf("\n"); # endif f_num++; } /* include stuff from librarys */ f_num=0; while (f_num