mirror of
https://github.com/elliotnunn/NetBoot.git
synced 2024-09-01 00:28:57 +00:00
1706 lines
43 KiB
C
1706 lines
43 KiB
C
/* vasm.c main module for vasm */
|
|
/* (c) in 2002-2020 by Volker Barthelmann */
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
|
|
#include "vasm.h"
|
|
#include "osdep.h"
|
|
#include "stabs.h"
|
|
#include "dwarf.h"
|
|
|
|
#define _VER "vasm 1.8h"
|
|
char *copyright = _VER " (c) in 2002-2020 Volker Barthelmann";
|
|
#ifdef AMIGA
|
|
static const char *_ver = "$VER: " _VER " " __AMIGADATE__ "\r\n";
|
|
#endif
|
|
|
|
#define SRCREADINC (64*1024) /* extend buffer in these steps when reading */
|
|
|
|
/* The resolver will run another pass over the current section as long as any
|
|
label location or atom size has changed. It gives up at MAXPASSES, which
|
|
hopefully will never happen.
|
|
During the first FASTOPTPHASE passes all instructions of a section will be
|
|
optimized at the same time. After that the resolver enters a safe mode,
|
|
where only a single instruction per pass is changed. */
|
|
#define MAXPASSES 1000
|
|
#define FASTOPTPHASE 200
|
|
|
|
source *cur_src;
|
|
char *filename,*debug_filename;
|
|
section *current_section;
|
|
char *inname,*outname,*listname,*compile_dir;
|
|
taddr inst_alignment;
|
|
int done,secname_attr,unnamed_sections,ignore_multinc,nocase,no_symbols;
|
|
int pic_check,final_pass,debug,exec_out,chklabels,warn_unalloc_ini_dat;
|
|
int nostdout;
|
|
int listena,listformfeed=1,listlinesperpage=40,listnosyms;
|
|
listing *first_listing,*last_listing,*cur_listing;
|
|
struct stabdef *first_nlist,*last_nlist;
|
|
char *output_format="test";
|
|
unsigned long long taddrmask;
|
|
taddr taddrmin,taddrmax;
|
|
char emptystr[]="";
|
|
char vasmsym_name[]="__VASM";
|
|
int num_secs;
|
|
|
|
static int produce_listing;
|
|
static char **listtitles;
|
|
static int *listtitlelines;
|
|
static int listtitlecnt;
|
|
|
|
static FILE *outfile;
|
|
|
|
static int depend,depend_all;
|
|
#define DEPEND_LIST 1
|
|
#define DEPEND_MAKE 2
|
|
struct deplist {
|
|
struct deplist *next;
|
|
char *filename;
|
|
};
|
|
static struct deplist *first_depend,*last_depend;
|
|
static char *dep_filename;
|
|
|
|
static section *first_section,*last_section;
|
|
#if NOT_NEEDED
|
|
static section *prev_sec,*prev_org;
|
|
#endif
|
|
|
|
/* MNEMOHTABSIZE should be defined by cpu module */
|
|
#ifndef MNEMOHTABSIZE
|
|
#define MNEMOHTABSIZE 0x1000
|
|
#endif
|
|
hashtable *mnemohash;
|
|
|
|
static int dwarf;
|
|
static int verbose=1,auto_import=1;
|
|
static int fail_on_warning;
|
|
static taddr sec_padding;
|
|
static struct include_path *first_incpath;
|
|
static struct source_file *first_source;
|
|
|
|
static char *output_copyright;
|
|
static void (*write_object)(FILE *,section *,symbol *);
|
|
static int (*output_args)(char *);
|
|
|
|
|
|
void leave(void)
|
|
{
|
|
section *sec;
|
|
symbol *sym;
|
|
|
|
if(outfile){
|
|
fclose(outfile);
|
|
if (errors&&outname!=NULL)
|
|
remove(outname);
|
|
}
|
|
|
|
if(debug){
|
|
fprintf(stdout,"Sections:\n");
|
|
for(sec=first_section;sec;sec=sec->next)
|
|
print_section(stdout,sec);
|
|
|
|
fprintf(stdout,"Symbols:\n");
|
|
for(sym=first_symbol;sym;sym=sym->next){
|
|
print_symbol(stdout,sym);
|
|
fprintf(stdout,"\n");
|
|
}
|
|
}
|
|
|
|
if(errors||(fail_on_warning&&warnings))
|
|
exit(EXIT_FAILURE);
|
|
else
|
|
exit(EXIT_SUCCESS);
|
|
}
|
|
|
|
/* Convert all labels from an offset-section into absolute expressions. */
|
|
static void convert_offset_labels(void)
|
|
{
|
|
symbol *sym;
|
|
|
|
for (sym=first_symbol; sym; sym=sym->next) {
|
|
if (sym->type==LABSYM && sym->sec!=NULL && (sym->sec->flags&UNALLOCATED)) {
|
|
sym->type = EXPRESSION;
|
|
sym->expr = number_expr(sym->pc);
|
|
sym->sec = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Removes all unallocated (offset) sections from the list. */
|
|
static void remove_unalloc_sects(void)
|
|
{
|
|
section *prev,*sec;
|
|
|
|
for (sec=first_section,prev=NULL; sec; sec=sec->next) {
|
|
if (sec->flags&UNALLOCATED) {
|
|
if (prev)
|
|
prev->next = sec->next;
|
|
else
|
|
first_section = sec->next;
|
|
}
|
|
else
|
|
prev = sec;
|
|
}
|
|
last_section = prev;
|
|
}
|
|
|
|
/* convert reloffs-atom into one or more space-atoms */
|
|
static void roffs_to_space(section *sec,atom *p)
|
|
{
|
|
uint8_t padding[MAXPADBYTES];
|
|
taddr space,padbytes,n;
|
|
sblock *sb = NULL;
|
|
|
|
if (eval_expr(p->content.roffs->offset,&space,sec,sec->pc) &&
|
|
(p->content.roffs->fillval==NULL ||
|
|
eval_expr(p->content.roffs->fillval,&n,sec,sec->pc))) {
|
|
space = sec->org + space - sec->pc;
|
|
|
|
if (space >= 0) {
|
|
if (p->content.roffs->fillval == NULL) {
|
|
memcpy(padding,sec->pad,MAXPADBYTES);
|
|
padbytes = sec->padbytes;
|
|
}
|
|
else
|
|
padbytes = make_padding(n,padding,MAXPADBYTES);
|
|
|
|
if (space >= padbytes) {
|
|
n = balign(sec->pc,padbytes); /* alignment is automatic */
|
|
space -= n;
|
|
sec->pc += n; /* Important! Fix the PC for new alignment. */
|
|
sb = new_sblock(number_expr(space/padbytes),padbytes,0);
|
|
memcpy(sb->fill,padding,padbytes);
|
|
p->type = SPACE;
|
|
p->content.sb = sb;
|
|
p->align = padbytes;
|
|
|
|
space %= padbytes;
|
|
if (space > 0) {
|
|
/* fill the rest with zeros */
|
|
atom *a = new_space_atom(number_expr(space),1,0);
|
|
a->next = p->next;
|
|
p->next = a;
|
|
}
|
|
}
|
|
else {
|
|
p->type = SPACE;
|
|
p->content.sb = new_sblock(number_expr(space),1,0);
|
|
}
|
|
}
|
|
else
|
|
general_error(20); /* rorg is lower than current pc */
|
|
}
|
|
else
|
|
general_error(30); /* expression must be constant */
|
|
}
|
|
|
|
/* append a new stabs (nlist) symbol/debugging definition */
|
|
static void new_stabdef(aoutnlist *nlist,section *sec)
|
|
{
|
|
struct stabdef *new = mymalloc(sizeof(struct stabdef));
|
|
|
|
new->next = NULL;
|
|
new->name.ptr = nlist->name;
|
|
new->type = nlist->type;
|
|
new->other = nlist->other;
|
|
new->desc = nlist->desc;
|
|
new->base = NULL;
|
|
if (nlist->value == NULL)
|
|
new->value = 0;
|
|
else if (!eval_expr(nlist->value,&new->value,sec,sec->pc)) {
|
|
int btype = find_base(nlist->value,&new->base,sec,sec->pc);
|
|
if (btype==BASE_ILLEGAL || btype==BASE_PCREL) {
|
|
new->base = NULL;
|
|
general_error(38); /* illegal relocation */
|
|
}
|
|
else if (new->base != NULL)
|
|
new->base->flags |= REFERENCED;
|
|
}
|
|
if (last_nlist)
|
|
last_nlist = last_nlist->next = new;
|
|
else
|
|
first_nlist = last_nlist = new;
|
|
}
|
|
|
|
/* emit internal debug info, triggered by a VASMDEBUG atom */
|
|
void vasmdebug(const char *f,section *s,atom *a)
|
|
{
|
|
if (a->next != NULL) {
|
|
a = a->next;
|
|
printf("%s: (%s+0x%llx) %2d:%lu(%u) ",
|
|
f,s->name,ULLTADDR(s->pc),a->type,(unsigned long)a->lastsize,a->changes);
|
|
print_atom(stdout,a);
|
|
putchar('\n');
|
|
}
|
|
}
|
|
|
|
static int resolve_section(section *sec)
|
|
{
|
|
taddr rorg_pc,org_pc;
|
|
int fastphase=FASTOPTPHASE;
|
|
int pass=0;
|
|
int extrapass,rorg;
|
|
size_t size;
|
|
atom *p;
|
|
|
|
do{
|
|
done=1;
|
|
rorg=0;
|
|
if (++pass>=MAXPASSES){
|
|
general_error(7,sec->name);
|
|
break;
|
|
}
|
|
extrapass=pass<=fastphase;
|
|
if(debug)
|
|
printf("resolve_section(%s) pass %d%s",sec->name,pass,
|
|
pass<=fastphase?" (fast)\n":"\n");
|
|
sec->pc=sec->org;
|
|
for(p=sec->first;p;p=p->next){
|
|
sec->pc=pcalign(p,sec->pc);
|
|
if(cur_src=p->src)
|
|
cur_src->line=p->line;
|
|
#if HAVE_CPU_OPTS
|
|
if(p->type==OPTS){
|
|
cpu_opts(p->content.opts);
|
|
}
|
|
else
|
|
#endif
|
|
if(p->type==RORG){
|
|
if(rorg)
|
|
general_error(43); /* reloc org is already set */
|
|
rorg_pc=*p->content.rorg;
|
|
org_pc=sec->pc;
|
|
sec->pc=rorg_pc;
|
|
sec->flags|=ABSOLUTE;
|
|
rorg=1;
|
|
}
|
|
else if(p->type==RORGEND&&rorg){
|
|
sec->pc=org_pc+(sec->pc-rorg_pc);
|
|
rorg_pc=0;
|
|
sec->flags&=~ABSOLUTE;
|
|
rorg=0;
|
|
}
|
|
else if(p->type==LABEL){
|
|
symbol *label=p->content.label;
|
|
if(label->type!=LABSYM)
|
|
ierror(0);
|
|
if(label->pc!=sec->pc){
|
|
if(debug)
|
|
printf("moving label %s from %lu to %lu\n",label->name,
|
|
(unsigned long)label->pc,(unsigned long)sec->pc);
|
|
done=0;
|
|
label->pc=sec->pc;
|
|
}
|
|
}
|
|
else if(p->type==VASMDEBUG)
|
|
vasmdebug("resolve_section",sec,p);
|
|
if(pass>fastphase&&!done&&p->type==INSTRUCTION){
|
|
/* entered safe mode: optimize only one instruction every pass */
|
|
sec->pc+=p->lastsize;
|
|
continue;
|
|
}
|
|
if(p->changes>MAXSIZECHANGES){
|
|
/* atom changed size too frequently, set warning flag */
|
|
if(debug)
|
|
printf("setting resolve-warning flag for atom type %d at %lu\n",
|
|
p->type,(unsigned long)sec->pc);
|
|
sec->flags|=RESOLVE_WARN;
|
|
size=atom_size(p,sec,sec->pc);
|
|
sec->flags&=~RESOLVE_WARN;
|
|
}
|
|
else
|
|
size=atom_size(p,sec,sec->pc);
|
|
if(size!=p->lastsize){
|
|
if(debug)
|
|
printf("modify size of atom type %d at %lu from %lu to %lu\n",
|
|
p->type,(unsigned long)sec->pc,(unsigned long)p->lastsize,
|
|
(unsigned long)size);
|
|
done=0;
|
|
if(pass>fastphase)
|
|
p->changes++; /* now count size modifications of atoms */
|
|
else if(size>p->lastsize)
|
|
extrapass=0; /* no extra pass, when an atom became larger */
|
|
p->lastsize=size;
|
|
}
|
|
sec->pc+=size;
|
|
}
|
|
if(rorg){
|
|
sec->pc=org_pc+(sec->pc-rorg_pc);
|
|
sec->flags&=~ABSOLUTE; /* workaround for misssing RORGEND */
|
|
}
|
|
/* Extend the fast-optimization phase, when there was no atom which
|
|
became larger than in the previous pass. */
|
|
if(extrapass) fastphase++;
|
|
}while(errors==0&&!done);
|
|
return pass;
|
|
}
|
|
|
|
static void bvunite(bvtype *dest,bvtype *src,size_t len)
|
|
{
|
|
len/=sizeof(bvtype);
|
|
for(;len>0;len--)
|
|
*dest++|=*src++;
|
|
}
|
|
|
|
static void resolve(void)
|
|
{
|
|
section *sec;
|
|
bvtype *todo;
|
|
int finished;
|
|
|
|
final_pass=0;
|
|
if(debug)
|
|
printf("resolve()\n");
|
|
|
|
for(num_secs=0, sec=first_section;sec;sec=sec->next)
|
|
sec->idx=num_secs++;
|
|
|
|
todo=mymalloc(BVSIZE(num_secs));
|
|
memset(todo,~(bvtype)0,BVSIZE(num_secs));
|
|
|
|
do{
|
|
finished=1;
|
|
for(sec=first_section;sec;sec=sec->next)
|
|
if(BTST(todo, sec->idx)){
|
|
int passes;
|
|
finished=0;
|
|
passes = resolve_section(sec);
|
|
BCLR(todo, sec->idx);
|
|
if(passes>1){
|
|
if(sec->deps)
|
|
bvunite(todo, sec->deps, BVSIZE(num_secs));
|
|
}
|
|
}
|
|
}while(!finished);
|
|
}
|
|
|
|
static void assemble(void)
|
|
{
|
|
taddr basepc,rorg_pc,org_pc;
|
|
struct dwarf_info dinfo;
|
|
int bss,rorg;
|
|
section *sec;
|
|
atom *p;
|
|
|
|
convert_offset_labels();
|
|
if(dwarf){
|
|
dinfo.version=dwarf;
|
|
dinfo.producer=cnvstr(copyright,strchr(copyright,'(')-copyright-1);
|
|
dwarf_init(&dinfo,first_incpath,first_source);
|
|
}
|
|
final_pass=1;
|
|
rorg=0;
|
|
for(sec=first_section;sec;sec=sec->next){
|
|
source *lasterrsrc=NULL;
|
|
utaddr oldpc;
|
|
int lasterrline=0,ovflw=0;
|
|
sec->pc=sec->org;
|
|
bss=strchr(sec->attr,'u')!=NULL;
|
|
for(p=sec->first;p;p=p->next){
|
|
basepc=sec->pc;
|
|
sec->pc=pcalign(p,sec->pc);
|
|
if(cur_src=p->src)
|
|
cur_src->line=p->line;
|
|
if(p->list&&p->list->atom==p){
|
|
p->list->sec=sec;
|
|
p->list->pc=sec->pc;
|
|
}
|
|
if(p->changes>MAXSIZECHANGES)
|
|
sec->flags|=RESOLVE_WARN;
|
|
/* print a warning on auto-aligned instructions or data */
|
|
if(sec->pc!=basepc){
|
|
atom *aa;
|
|
if (p->type==LABEL&&p->next!=NULL&&p->next->line==p->line)
|
|
aa=p->next; /* next atom in same line, look at it instead of label */
|
|
else
|
|
aa=p;
|
|
if (aa->type==INSTRUCTION)
|
|
general_error(50); /* instruction has been auto-aligned */
|
|
else if (aa->type==DATA||aa->type==DATADEF)
|
|
general_error(57); /* data has been auto-aligned */
|
|
}
|
|
if(p->type==RORG){
|
|
rorg_pc=*p->content.rorg;
|
|
org_pc=sec->pc;
|
|
sec->pc=rorg_pc;
|
|
sec->flags|=ABSOLUTE;
|
|
rorg=1;
|
|
}
|
|
else if(p->type==RORGEND){
|
|
if(rorg){
|
|
sec->pc=org_pc+(sec->pc-rorg_pc);
|
|
rorg_pc=0;
|
|
sec->flags&=~ABSOLUTE;
|
|
rorg=0;
|
|
}
|
|
else
|
|
general_error(44); /* reloc org was not set */
|
|
}
|
|
else if(p->type==INSTRUCTION){
|
|
dblock *db;
|
|
cur_listing=p->list;
|
|
db=eval_instruction(p->content.inst,sec,sec->pc);
|
|
if(pic_check)
|
|
do_pic_check(db->relocs);
|
|
cur_listing=0;
|
|
if(debug){
|
|
if(db->size!=(p->content.inst->code>=0?
|
|
instruction_size(p->content.inst,sec,sec->pc):0))
|
|
ierror(0);
|
|
}
|
|
if(dwarf){
|
|
if(cur_src->defsrc)
|
|
dwarf_line(&dinfo,sec,cur_src->defsrc->srcfile->index,
|
|
cur_src->defline+cur_src->line);
|
|
else
|
|
dwarf_line(&dinfo,sec,cur_src->srcfile->index,cur_src->line);
|
|
}
|
|
/*FIXME: sauber freigeben */
|
|
myfree(p->content.inst);
|
|
p->content.db=db;
|
|
p->type=DATA;
|
|
}
|
|
else if(p->type==DATADEF){
|
|
dblock *db;
|
|
cur_listing=p->list;
|
|
db=eval_data(p->content.defb->op,p->content.defb->bitsize,sec,sec->pc);
|
|
if(pic_check)
|
|
do_pic_check(db->relocs);
|
|
cur_listing=0;
|
|
/*FIXME: sauber freigeben */
|
|
myfree(p->content.defb);
|
|
p->content.db=db;
|
|
p->type=DATA;
|
|
}
|
|
else if(p->type==ROFFS)
|
|
roffs_to_space(sec,p);
|
|
#if HAVE_CPU_OPTS
|
|
else if(p->type==OPTS)
|
|
cpu_opts(p->content.opts);
|
|
#endif
|
|
else if(p->type==PRINTTEXT&&!nostdout)
|
|
printf("%s",p->content.ptext);
|
|
else if(p->type==PRINTEXPR&&!nostdout)
|
|
atom_printexpr(p->content.pexpr,sec,sec->pc);
|
|
else if(p->type==ASSERT){
|
|
assertion *ast=p->content.assert;
|
|
taddr val;
|
|
if(ast->assert_exp!=NULL) {
|
|
eval_expr(ast->assert_exp,&val,sec,sec->pc);
|
|
if(val==0)
|
|
general_error(47,ast->expstr,ast->msgstr?ast->msgstr:emptystr);
|
|
}
|
|
else /* ASSERT without expression, used for user-FAIL directives */
|
|
general_error(19,ast->msgstr?ast->msgstr:emptystr);
|
|
}
|
|
else if(p->type==NLIST)
|
|
new_stabdef(p->content.nlist,sec);
|
|
else if(p->type==VASMDEBUG)
|
|
vasmdebug("assemble",sec,p);
|
|
if(p->type==DATA&&bss){
|
|
if(lasterrsrc!=p->src||lasterrline!=p->line){
|
|
if(sec->flags&UNALLOCATED){
|
|
if(warn_unalloc_ini_dat)
|
|
general_error(54); /* initialized data in offset section */
|
|
}
|
|
else
|
|
general_error(31); /* initialized data in bss */
|
|
lasterrsrc=p->src;
|
|
lasterrline=p->line;
|
|
}
|
|
}
|
|
oldpc=sec->pc;
|
|
sec->pc+=atom_size(p,sec,sec->pc);
|
|
if((utaddr)sec->pc!=oldpc){
|
|
if((utaddr)(sec->pc-1)<oldpc||ovflw)
|
|
general_error(45); /* address space overflow */
|
|
ovflw=sec->pc==0;
|
|
}
|
|
sec->flags&=~RESOLVE_WARN;
|
|
}
|
|
/* leave RORG-mode, when section ends */
|
|
if(rorg){
|
|
sec->pc=org_pc+(sec->pc-rorg_pc);
|
|
rorg_pc=0;
|
|
sec->flags&=~ABSOLUTE;
|
|
rorg=0;
|
|
}
|
|
if(dwarf)
|
|
dwarf_end_sequence(&dinfo,sec);
|
|
}
|
|
remove_unalloc_sects();
|
|
if(dwarf)
|
|
dwarf_finish(&dinfo);
|
|
}
|
|
|
|
static void undef_syms(void)
|
|
{
|
|
symbol *sym;
|
|
|
|
for(sym=first_symbol;sym;sym=sym->next){
|
|
if (!auto_import&&sym->type==IMPORT&&!(sym->flags&(EXPORT|COMMON|WEAK)))
|
|
general_error(22,sym->name);
|
|
else if (sym->type==IMPORT&&!(sym->flags&REFERENCED))
|
|
general_error(61,sym->name);
|
|
}
|
|
}
|
|
|
|
static void fix_labels(void)
|
|
{
|
|
symbol *sym,*base;
|
|
taddr val;
|
|
|
|
for(sym=first_symbol;sym;sym=sym->next){
|
|
/* turn all absolute mode labels into absolute symbols */
|
|
if((sym->flags&ABSLABEL)&&sym->type==LABSYM){
|
|
sym->type=EXPRESSION;
|
|
sym->flags&=~(TYPE_MASK|COMMON);
|
|
sym->sec=NULL;
|
|
sym->size=NULL;
|
|
sym->align=0;
|
|
sym->expr=number_expr(sym->pc);
|
|
}
|
|
/* expressions which are based on a label are turned into a new label */
|
|
else if(sym->type==EXPRESSION){
|
|
if(!eval_expr(sym->expr,&val,NULL,0)){
|
|
if(find_base(sym->expr,&base,NULL,0)==BASE_OK){
|
|
/* turn into an offseted label symbol from the base's section */
|
|
sym->type=base->type;
|
|
sym->sec=base->sec;
|
|
sym->pc=val;
|
|
sym->align=1;
|
|
}else
|
|
general_error(53,sym->name); /* non-relocatable expr. in equate */
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void statistics(void)
|
|
{
|
|
section *sec;
|
|
unsigned long long size;
|
|
|
|
printf("\n");
|
|
for(sec=first_section;sec;sec=sec->next){
|
|
size=ULLTADDR(ULLTADDR(sec->pc)-ULLTADDR(sec->org));
|
|
printf("%s(%s%lu):\t%12llu byte%c\n",sec->name,sec->attr,
|
|
(unsigned long)sec->align,size,size==1?' ':'s');
|
|
}
|
|
}
|
|
|
|
static int init_output(char *fmt)
|
|
{
|
|
if(!strcmp(fmt,"test"))
|
|
return init_output_test(&output_copyright,&write_object,&output_args);
|
|
if(!strcmp(fmt,"elf"))
|
|
return init_output_elf(&output_copyright,&write_object,&output_args);
|
|
if(!strcmp(fmt,"bin"))
|
|
return init_output_bin(&output_copyright,&write_object,&output_args);
|
|
if(!strcmp(fmt,"srec"))
|
|
return init_output_srec(&output_copyright,&write_object,&output_args);
|
|
if(!strcmp(fmt,"vobj"))
|
|
return init_output_vobj(&output_copyright,&write_object,&output_args);
|
|
if(!strcmp(fmt,"hunk"))
|
|
return init_output_hunk(&output_copyright,&write_object,&output_args);
|
|
if(!strcmp(fmt,"aout"))
|
|
return init_output_aout(&output_copyright,&write_object,&output_args);
|
|
if(!strcmp(fmt,"hunkexe")){
|
|
exec_out=1; /* executable format */
|
|
return init_output_hunk(&output_copyright,&write_object,&output_args);
|
|
}
|
|
if(!strcmp(fmt,"tos")){
|
|
exec_out=1; /* executable format */
|
|
return init_output_tos(&output_copyright,&write_object,&output_args);
|
|
}
|
|
if(!strcmp(fmt,"xfile")){
|
|
exec_out=1; /* executable format */
|
|
return init_output_xfile(&output_copyright,&write_object,&output_args);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int init_main(void)
|
|
{
|
|
size_t i;
|
|
char *last;
|
|
hashdata data;
|
|
mnemohash=new_hashtable(MNEMOHTABSIZE);
|
|
i=0;
|
|
while(i<mnemonic_cnt){
|
|
data.idx=i;
|
|
last=mnemonics[i].name;
|
|
add_hashentry(mnemohash,mnemonics[i].name,data);
|
|
do{
|
|
i++;
|
|
}while(i<mnemonic_cnt&&!strcmp(last,mnemonics[i].name));
|
|
}
|
|
if(debug){
|
|
if(mnemohash->collisions)
|
|
printf("*** %d mnemonic collisions!!\n",mnemohash->collisions);
|
|
}
|
|
new_include_path(""); /* index 0: current work directory */
|
|
taddrmask=MAKEMASK(bytespertaddr<<3);
|
|
taddrmax=((utaddr)~0)>>1;
|
|
taddrmin=~taddrmax;
|
|
inst_alignment=INST_ALIGN;
|
|
return 1;
|
|
}
|
|
|
|
void set_default_output_format(char *fmt)
|
|
{
|
|
output_format=fmt;
|
|
}
|
|
|
|
static void include_main_source(void)
|
|
{
|
|
if (inname) {
|
|
char *filepart;
|
|
|
|
if ((filepart = get_filepart(inname)) != inname) {
|
|
/* main source is not in current dir., set compile-directory path */
|
|
compile_dir = cnvstr(inname,filepart-inname);
|
|
new_include_path(compile_dir);
|
|
}
|
|
else
|
|
compile_dir = NULL;
|
|
|
|
if (include_source(filepart)) {
|
|
setfilename(filepart);
|
|
setdebugname(inname);
|
|
}
|
|
}
|
|
else
|
|
general_error(15);
|
|
}
|
|
|
|
static void write_depends(FILE *f)
|
|
{
|
|
struct deplist *d = first_depend;
|
|
|
|
if (depend==DEPEND_MAKE && d!=NULL && outname!=NULL)
|
|
fprintf(f,"%s:",outname);
|
|
|
|
while (d != NULL) {
|
|
switch (depend) {
|
|
case DEPEND_LIST:
|
|
fprintf(f,"%s\n",d->filename);
|
|
break;
|
|
case DEPEND_MAKE:
|
|
if (str_is_graph(d->filename))
|
|
fprintf(f," %s",d->filename);
|
|
else
|
|
fprintf(f," \"%s\"",d->filename);
|
|
break;
|
|
default:
|
|
ierror(0);
|
|
}
|
|
d = d->next;
|
|
}
|
|
|
|
if (depend == DEPEND_MAKE)
|
|
fputc('\n',f);
|
|
}
|
|
|
|
int main(int argc,char **argv)
|
|
{
|
|
int i;
|
|
for(i=1;i<argc;i++){
|
|
if(argv[i][0]=='-'&&argv[i][1]=='F'){
|
|
output_format=argv[i]+2;
|
|
argv[i][0]=0;
|
|
}
|
|
if(!strcmp("-quiet",argv[i])){
|
|
verbose=0;
|
|
argv[i][0]=0;
|
|
}
|
|
if(!strcmp("-debug",argv[i])){
|
|
debug=1;
|
|
argv[i][0]=0;
|
|
}
|
|
}
|
|
if(!init_output(output_format))
|
|
general_error(16,output_format);
|
|
if(!init_main())
|
|
general_error(10,"main");
|
|
if(!init_symbol())
|
|
general_error(10,"symbol");
|
|
if(verbose)
|
|
printf("%s\n%s\n%s\n%s\n",copyright,cpu_copyright,syntax_copyright,output_copyright);
|
|
for(i=1;i<argc;i++){
|
|
if(argv[i][0]==0)
|
|
continue;
|
|
if(argv[i][0]!='-'){
|
|
if(inname)
|
|
general_error(11);
|
|
inname=argv[i];
|
|
continue;
|
|
}
|
|
if(!strcmp("-o",argv[i])&&i<argc-1){
|
|
if(outname)
|
|
general_error(28,argv[i]);
|
|
outname=argv[++i];
|
|
continue;
|
|
}
|
|
if(!strcmp("-L",argv[i])&&i<argc-1){
|
|
if(listname)
|
|
general_error(28,argv[i]);
|
|
listname=argv[++i];
|
|
produce_listing=1;
|
|
set_listing(1);
|
|
continue;
|
|
}
|
|
if(!strcmp("-Lnf",argv[i])){
|
|
listformfeed=0;
|
|
continue;
|
|
}
|
|
if(!strcmp("-Lns",argv[i])){
|
|
listnosyms=1;
|
|
continue;
|
|
}
|
|
if(!strncmp("-Ll",argv[i],3)){
|
|
sscanf(argv[i]+3,"%i",&listlinesperpage);
|
|
continue;
|
|
}
|
|
if(!strncmp("-D",argv[i],2)){
|
|
char *def=NULL;
|
|
expr *val;
|
|
if(argv[i][2])
|
|
def=&argv[i][2];
|
|
else if (i<argc-1)
|
|
def=argv[++i];
|
|
if(def){
|
|
char *s=def;
|
|
if(ISIDSTART(*s)){
|
|
s++;
|
|
while(ISIDCHAR(*s))
|
|
s++;
|
|
def=cnvstr(def,s-def);
|
|
if(*s=='='){
|
|
s++;
|
|
val=parse_expr(&s);
|
|
}
|
|
else
|
|
val=number_expr(1);
|
|
if(*s)
|
|
general_error(23,'D'); /* trailing garbage after option */
|
|
new_abs(def,val);
|
|
myfree(def);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
if(!strncmp("-I",argv[i],2)){
|
|
char *path=NULL;
|
|
if(argv[i][2])
|
|
path=&argv[i][2];
|
|
else if (i<argc-1)
|
|
path=argv[++i];
|
|
if(path){
|
|
new_include_path(path);
|
|
continue;
|
|
}
|
|
}
|
|
if(!strncmp("-depend=",argv[i],8) || !strncmp("-dependall=",argv[i],11)){
|
|
depend_all=argv[i][7]!='=';
|
|
if(!strcmp("list",&argv[i][depend_all?11:8])){
|
|
depend=DEPEND_LIST;
|
|
continue;
|
|
}
|
|
else if(!strcmp("make",&argv[i][depend_all?11:8])){
|
|
depend=DEPEND_MAKE;
|
|
continue;
|
|
}
|
|
}
|
|
if(!strcmp("-depfile",argv[i])&&i<argc-1){
|
|
if(dep_filename)
|
|
general_error(28,argv[i]);
|
|
dep_filename=argv[++i];
|
|
continue;
|
|
}
|
|
if(!strcmp("-unnamed-sections",argv[i])){
|
|
unnamed_sections=1;
|
|
continue;
|
|
}
|
|
if(!strcmp("-ignore-mult-inc",argv[i])){
|
|
ignore_multinc=1;
|
|
continue;
|
|
}
|
|
if(!strcmp("-nocase",argv[i])){
|
|
nocase=1;
|
|
continue;
|
|
}
|
|
if(!strcmp("-nosym",argv[i])){
|
|
no_symbols=1;
|
|
continue;
|
|
}
|
|
if(!strncmp("-nowarn=",argv[i],8)){
|
|
int wno;
|
|
sscanf(argv[i]+8,"%i",&wno);
|
|
disable_warning(wno);
|
|
continue;
|
|
}
|
|
else if(!strcmp("-w",argv[i])){
|
|
no_warn=1;
|
|
continue;
|
|
}
|
|
else if(!strcmp("-wfail",argv[i])){
|
|
fail_on_warning=1;
|
|
continue;
|
|
}
|
|
if(!strncmp("-maxerrors=",argv[i],11)){
|
|
sscanf(argv[i]+11,"%i",&max_errors);
|
|
continue;
|
|
}
|
|
else if(!strcmp("-pic",argv[i])){
|
|
pic_check=1;
|
|
continue;
|
|
}
|
|
else if(!strncmp("-maxmacrecurs=",argv[i],14)){
|
|
sscanf(argv[i]+14,"%i",&maxmacrecurs);
|
|
continue;
|
|
}
|
|
else if(!strcmp("-unsshift",argv[i])){
|
|
unsigned_shift=1;
|
|
continue;
|
|
}
|
|
else if(!strcmp("-chklabels",argv[i])){
|
|
chklabels=1;
|
|
continue;
|
|
}
|
|
else if(!strcmp("-noialign",argv[i])){
|
|
inst_alignment=1;
|
|
continue;
|
|
}
|
|
else if(!strncmp("-dwarf",argv[i],6)){
|
|
if(argv[i][6]=='=')
|
|
sscanf(argv[i]+7,"%i",&dwarf); /* get DWARF version */
|
|
else
|
|
dwarf=3; /* default to DWARF3 */
|
|
continue;
|
|
}
|
|
else if(!strncmp("-pad=",argv[i],5)){
|
|
long long ullpadding;
|
|
sscanf(argv[i]+5,"%lli",&ullpadding);
|
|
sec_padding=(taddr)ullpadding;
|
|
continue;
|
|
}
|
|
if(cpu_args(argv[i]))
|
|
continue;
|
|
if(syntax_args(argv[i]))
|
|
continue;
|
|
if(output_args(argv[i]))
|
|
continue;
|
|
if(!strcmp("-esc",argv[i])){
|
|
esc_sequences=1;
|
|
continue;
|
|
}
|
|
if(!strcmp("-noesc",argv[i])){
|
|
esc_sequences=0;
|
|
continue;
|
|
}
|
|
if (!strncmp("-x",argv[i],2)){
|
|
auto_import=0;
|
|
continue;
|
|
}
|
|
general_error(14,argv[i]);
|
|
}
|
|
nostdout=depend&&dep_filename==NULL; /* dependencies to stdout nothing else */
|
|
include_main_source();
|
|
internal_abs(vasmsym_name);
|
|
if(!init_parse())
|
|
general_error(10,"parse");
|
|
if(!init_syntax())
|
|
general_error(10,"syntax");
|
|
if(!init_cpu())
|
|
general_error(10,"cpu");
|
|
parse();
|
|
listena=0;
|
|
if(errors==0||produce_listing)
|
|
resolve();
|
|
if(errors==0||produce_listing)
|
|
assemble();
|
|
cur_src=NULL;
|
|
if(errors==0)
|
|
undef_syms();
|
|
fix_labels();
|
|
if(produce_listing){
|
|
if(!listname)
|
|
listname="a.lst";
|
|
write_listing(listname);
|
|
}
|
|
if(errors==0){
|
|
if(depend&&dep_filename==NULL){
|
|
/* dependencies to stdout, no object output */
|
|
write_depends(stdout);
|
|
} else {
|
|
if(verbose)
|
|
statistics();
|
|
if(depend&&dep_filename!=NULL){
|
|
/* write dependencies to a named file first */
|
|
FILE *depfile = fopen(dep_filename,"w");
|
|
if (depfile){
|
|
write_depends(depfile);
|
|
fclose(depfile);
|
|
}
|
|
else
|
|
general_error(13,dep_filename);
|
|
}
|
|
/* write the object file */
|
|
if(!outname)
|
|
outname="a.out";
|
|
outfile=fopen(outname,"wb");
|
|
if(!outfile)
|
|
general_error(13,outname);
|
|
else
|
|
write_object(outfile,first_section,first_symbol);
|
|
}
|
|
}
|
|
leave();
|
|
return 0; /* not reached */
|
|
}
|
|
|
|
static void add_depend(char *name)
|
|
{
|
|
if (depend) {
|
|
struct deplist *d = first_depend;
|
|
|
|
/* check if an entry with the same file name already exists */
|
|
while (d != NULL) {
|
|
if (!strcmp(d->filename,name))
|
|
return;
|
|
d = d->next;
|
|
}
|
|
|
|
/* append new dependency record */
|
|
d = mymalloc(sizeof(struct deplist));
|
|
d->next = NULL;
|
|
if (name[0]=='.'&&(name[1]=='/'||name[1]=='\\'))
|
|
name += 2; /* skip "./" in paths */
|
|
d->filename = mystrdup(name);
|
|
if (last_depend)
|
|
last_depend = last_depend->next = d;
|
|
else
|
|
first_depend = last_depend = d;
|
|
}
|
|
}
|
|
|
|
static FILE *open_path(char *compdir,char *path,char *name,char *mode)
|
|
{
|
|
char pathbuf[MAXPATHLEN];
|
|
FILE *f;
|
|
|
|
if (strlen(compdir) + strlen(path) + strlen(name) + 1 <= MAXPATHLEN) {
|
|
strcpy(pathbuf,compdir);
|
|
strcat(pathbuf,path);
|
|
strcat(pathbuf,name);
|
|
|
|
if (f = fopen(pathbuf,mode)) {
|
|
if (depend_all || !abs_path(pathbuf))
|
|
add_depend(pathbuf);
|
|
return f;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
FILE *locate_file(char *filename,char *mode,struct include_path **ipath_used)
|
|
{
|
|
struct include_path *ipath;
|
|
FILE *f;
|
|
|
|
if (abs_path(filename)) {
|
|
/* file name is absolute, then don't use any include paths */
|
|
if (f = fopen(filename,mode)) {
|
|
if (depend_all)
|
|
add_depend(filename);
|
|
if (ipath_used)
|
|
*ipath_used = NULL; /* no path used, file name was absolute */
|
|
return f;
|
|
}
|
|
}
|
|
else {
|
|
/* locate file name in all known include paths */
|
|
for (ipath=first_incpath; ipath; ipath=ipath->next) {
|
|
if ((f = open_path("",ipath->path,filename,mode)) == NULL) {
|
|
if (compile_dir && !abs_path(ipath->path) &&
|
|
(f = open_path(compile_dir,ipath->path,filename,mode)))
|
|
ipath->compdir_based = 1;
|
|
}
|
|
if (f != NULL) {
|
|
if (ipath_used)
|
|
*ipath_used = ipath;
|
|
return f;
|
|
}
|
|
}
|
|
}
|
|
general_error(12,filename);
|
|
return NULL;
|
|
}
|
|
|
|
source *include_source(char *inc_name)
|
|
{
|
|
static int srcfileidx;
|
|
char *filename,*pathpart,*filepart;
|
|
struct source_file **nptr = &first_source;
|
|
struct source_file *srcfile;
|
|
source *newsrc = NULL;
|
|
FILE *f;
|
|
|
|
filename = convert_path(inc_name);
|
|
|
|
/* check whether this source file name was already included */
|
|
while (srcfile = *nptr) {
|
|
if (!filenamecmp(srcfile->name,filename)) {
|
|
myfree(filename);
|
|
nptr = NULL; /* reuse existing source in memory */
|
|
break;
|
|
}
|
|
nptr = &srcfile->next;
|
|
}
|
|
|
|
if (nptr != NULL) {
|
|
/* allocate, locate and read a new source file */
|
|
struct include_path *ipath;
|
|
|
|
if (f = locate_file(filename,"r",&ipath)) {
|
|
char *text;
|
|
size_t size;
|
|
|
|
for (text=NULL,size=0; ; size+=SRCREADINC) {
|
|
size_t nchar;
|
|
text = myrealloc(text,size+SRCREADINC);
|
|
nchar = fread(text+size,1,SRCREADINC,f);
|
|
if (nchar < SRCREADINC) {
|
|
size += nchar;
|
|
break;
|
|
}
|
|
}
|
|
if (feof(f)) {
|
|
if (size > 0) {
|
|
text = myrealloc(text,size+2);
|
|
*(text+size) = '\n';
|
|
*(text+size+1) = '\0';
|
|
size++;
|
|
}
|
|
else {
|
|
myfree(text);
|
|
text = "\n";
|
|
size = 1;
|
|
}
|
|
srcfile = mymalloc(sizeof(struct source_file));
|
|
srcfile->next = NULL;
|
|
srcfile->name = filename;
|
|
srcfile->incpath = ipath;
|
|
srcfile->text = text;
|
|
srcfile->size = size;
|
|
srcfile->index = ++srcfileidx;
|
|
*nptr = srcfile;
|
|
cur_src = newsrc = new_source(filename,srcfile,text,size);
|
|
}
|
|
else
|
|
general_error(29,filename);
|
|
fclose(f);
|
|
}
|
|
}
|
|
else {
|
|
/* same source was already loaded before, source_file node exists */
|
|
if (ignore_multinc)
|
|
return NULL; /* ignore multiple inclusion of this source completely */
|
|
|
|
/* new source instance from existing source file */
|
|
cur_src = newsrc = new_source(srcfile->name,srcfile,srcfile->text,
|
|
srcfile->size);
|
|
}
|
|
return newsrc;
|
|
}
|
|
|
|
/* searches a section by name and attr (if secname_attr set) */
|
|
section *find_section(char *name,char *attr)
|
|
{
|
|
section *p;
|
|
if(secname_attr){
|
|
for(p=first_section;p;p=p->next){
|
|
if(!strcmp(name,p->name) && !strcmp(attr,p->attr))
|
|
return p;
|
|
}
|
|
}
|
|
else{
|
|
for(p=first_section;p;p=p->next){
|
|
if(!strcmp(name,p->name))
|
|
return p;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* create a new source text instance, which has cur_src as parent */
|
|
source *new_source(char *srcname,struct source_file *srcfile,
|
|
char *text,size_t size)
|
|
{
|
|
static unsigned long id = 0;
|
|
source *s = mymalloc(sizeof(source));
|
|
size_t i;
|
|
char *p;
|
|
|
|
/* scan the source for strange characters */
|
|
for (p=text,i=0; i<size; i++,p++) {
|
|
if (*p == 0x1a) {
|
|
/* EOF character - replace by newline and ignore rest of source */
|
|
*p = '\n';
|
|
size = i + 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
s->parent = cur_src;
|
|
s->parent_line = cur_src ? cur_src->line : 0;
|
|
s->srcfile = srcfile; /* NULL for macros and repetitions */
|
|
s->name = mystrdup(srcname);
|
|
s->text = text;
|
|
s->size = size;
|
|
s->defsrc = NULL;
|
|
s->defline = 0;
|
|
s->macro = NULL;
|
|
s->repeat = 1; /* read just once */
|
|
s->irpname = NULL;
|
|
s->cond_level = clev; /* remember level of conditional nesting */
|
|
s->num_params = -1; /* not a macro, no parameters */
|
|
s->param[0] = emptystr;
|
|
s->param_len[0] = 0;
|
|
s->id = id++; /* every source has unique id - important for macros */
|
|
s->srcptr = text;
|
|
s->line = 0;
|
|
s->bufsize = INITLINELEN;
|
|
s->linebuf = mymalloc(INITLINELEN);
|
|
#ifdef CARGSYM
|
|
s->cargexp = NULL;
|
|
#endif
|
|
#ifdef REPTNSYM
|
|
/* -1 outside of a repetition block */
|
|
s->reptn = cur_src ? cur_src->reptn : -1;
|
|
#endif
|
|
return s;
|
|
}
|
|
|
|
/* quit parsing the current source instance, leave macros, repeat loops
|
|
and restore the conditional assembly level */
|
|
void end_source(source *s)
|
|
{
|
|
if(s){
|
|
s->srcptr=s->text+s->size;
|
|
s->repeat=1;
|
|
clev=s->cond_level;
|
|
}
|
|
}
|
|
|
|
/* try to find a matching section name for the given attributes */
|
|
static char *name_from_attr(char *attr)
|
|
{
|
|
while(*attr) {
|
|
switch(*attr++) {
|
|
case 'c': return "text";
|
|
case 'd': return "data";
|
|
case 'u': return "bss";
|
|
}
|
|
}
|
|
return emptystr;
|
|
}
|
|
|
|
/* set current section, remember last */
|
|
void set_section(section *s)
|
|
{
|
|
#if NOT_NEEDED
|
|
if (current_section!=NULL && !(current_section->flags & UNALLOCATED)) {
|
|
if (current_section->flags & ABSOLUTE)
|
|
prev_org = current_section;
|
|
else
|
|
prev_sec = current_section;
|
|
}
|
|
#endif
|
|
#if HAVE_CPU_OPTS
|
|
if (s!=NULL && !(s->flags & UNALLOCATED))
|
|
cpu_opts_init(s); /* set initial cpu opts before the first atom */
|
|
#endif
|
|
current_section = s;
|
|
}
|
|
|
|
/* creates a new section with given attributes and alignment;
|
|
does not switch to this section automatically */
|
|
section *new_section(char *name,char *attr,int align)
|
|
{
|
|
section *p;
|
|
if(unnamed_sections)
|
|
name=name_from_attr(attr);
|
|
if(p=find_section(name,attr))
|
|
return p;
|
|
p=mymalloc(sizeof(*p));
|
|
p->next=0;
|
|
p->deps=0;
|
|
p->name=mystrdup(name);
|
|
p->attr=mystrdup(attr);
|
|
p->first=p->last=0;
|
|
p->align=align;
|
|
p->org=p->pc=0;
|
|
p->flags=0;
|
|
p->memattr=0;
|
|
memset(p->pad,0,MAXPADBYTES);
|
|
if(sec_padding)
|
|
p->padbytes=make_padding(sec_padding,p->pad,MAXPADBYTES);
|
|
else
|
|
p->padbytes=1;
|
|
if(last_section)
|
|
last_section=last_section->next=p;
|
|
else
|
|
first_section=last_section=p;
|
|
return p;
|
|
}
|
|
|
|
/* create a dummy code section for each new ORG directive */
|
|
section *new_org(taddr org)
|
|
{
|
|
char buf[16];
|
|
section *sec;
|
|
|
|
sprintf(buf,"seg%llx",ULLTADDR(org));
|
|
sec = new_section(buf,"acrwx",1);
|
|
sec->org = sec->pc = org;
|
|
sec->flags |= ABSOLUTE; /* absolute destination address */
|
|
return sec;
|
|
}
|
|
|
|
/* switches current section to the section with the specified name */
|
|
void switch_section(char *name,char *attr)
|
|
{
|
|
section *p;
|
|
if(unnamed_sections)
|
|
name=name_from_attr(attr);
|
|
p=find_section(name,attr);
|
|
if(!p)
|
|
general_error(2,name);
|
|
else
|
|
set_section(p);
|
|
}
|
|
|
|
/* Switches current section to an offset section. Create a new section when
|
|
it doesn't exist yet or needs a different offset. */
|
|
void switch_offset_section(char *name,taddr offs)
|
|
{
|
|
static unsigned long id;
|
|
char unique_name[14];
|
|
section *sec;
|
|
|
|
if (!name) {
|
|
if (offs != -1)
|
|
++id;
|
|
sprintf(unique_name,"OFFSET%06lu",id);
|
|
name = unique_name;
|
|
}
|
|
sec = new_section(name,"u",1);
|
|
sec->flags |= UNALLOCATED;
|
|
if (offs != -1)
|
|
sec->org = sec->pc = offs;
|
|
set_section(sec);
|
|
}
|
|
|
|
/* returns current_section or the syntax module's default section,
|
|
when undefined */
|
|
section *default_section(void)
|
|
{
|
|
section *sec = current_section;
|
|
|
|
if (!sec && defsectname && defsecttype) {
|
|
sec = new_section(defsectname,defsecttype,1);
|
|
switch_section(defsectname,defsecttype);
|
|
}
|
|
return sec;
|
|
}
|
|
|
|
#if NOT_NEEDED
|
|
/* restore last relocatable section */
|
|
section *restore_section(void)
|
|
{
|
|
if (prev_sec)
|
|
return prev_sec;
|
|
if (defsectname && defsecttype)
|
|
return new_section(defsectname,defsecttype,1);
|
|
return NULL; /* no previous section or default section defined */
|
|
}
|
|
|
|
/* restore last absolute section */
|
|
section *restore_org(void)
|
|
{
|
|
if (prev_org)
|
|
return prev_org;
|
|
return new_org(0); /* no previous org: default to ORG 0 */
|
|
}
|
|
#endif /* NOT_NEEDED */
|
|
|
|
/* end a relocated ORG block */
|
|
int end_rorg(void)
|
|
{
|
|
section *s = default_section();
|
|
|
|
if (s == NULL) {
|
|
general_error(3);
|
|
return 0;
|
|
}
|
|
if (s->flags & IN_RORG) {
|
|
add_atom(s,new_rorgend_atom());
|
|
if (s->flags & PREVABS)
|
|
s->flags |= ABSOLUTE;
|
|
else
|
|
s->flags &= ~ABSOLUTE;
|
|
s->flags &= ~IN_RORG;
|
|
return 1;
|
|
}
|
|
general_error(44); /* no Rorg block to end */
|
|
return 0;
|
|
}
|
|
|
|
/* end a relocated ORG block when currently active */
|
|
void try_end_rorg(void)
|
|
{
|
|
if (current_section!=NULL && (current_section->flags&IN_RORG))
|
|
end_rorg();
|
|
}
|
|
|
|
/* start a relocated ORG block */
|
|
void start_rorg(taddr rorg)
|
|
{
|
|
section *s = default_section();
|
|
|
|
if (s == NULL) {
|
|
general_error(3);
|
|
return;
|
|
}
|
|
if (s->flags & IN_RORG)
|
|
end_rorg(); /* we are already in a ROrg-block, so close it first */
|
|
add_atom(s,new_rorg_atom(rorg));
|
|
s->flags |= IN_RORG;
|
|
if (!(s->flags & ABSOLUTE)) {
|
|
s->flags &= ~PREVABS;
|
|
s->flags |= ABSOLUTE; /* make section absolute during the ROrg-block */
|
|
}
|
|
else
|
|
s->flags |= PREVABS;
|
|
}
|
|
|
|
void print_section(FILE *f,section *sec)
|
|
{
|
|
atom *p;
|
|
taddr pc=sec->org;
|
|
fprintf(f,"section %s (attr=<%s> align=%llu):\n",
|
|
sec->name,sec->attr,ULLTADDR(sec->align));
|
|
for(p=sec->first;p;p=p->next){
|
|
pc=pcalign(p,pc);
|
|
fprintf(f,"%8llx: ",ULLTADDR(pc));
|
|
print_atom(f,p);
|
|
fprintf(f,"\n");
|
|
pc+=atom_size(p,sec,pc);
|
|
}
|
|
}
|
|
|
|
static struct include_path *new_ipath_node(char *pathname)
|
|
{
|
|
struct include_path *new = mymalloc(sizeof(struct include_path));
|
|
|
|
new->next = NULL;
|
|
new->path = pathname;
|
|
new->compdir_based = 0;
|
|
return new;
|
|
}
|
|
|
|
struct include_path *new_include_path(char *pathname)
|
|
{
|
|
struct include_path *ipath;
|
|
char *newpath = convert_path(pathname);
|
|
|
|
pathname = append_path_delimiter(newpath); /* append '/', when needed */
|
|
myfree(newpath);
|
|
|
|
/* check if path already exists, otherwise append new node */
|
|
for (ipath=first_incpath; ipath; ipath=ipath->next) {
|
|
if (!filenamecmp(pathname,ipath->path)) {
|
|
myfree(pathname);
|
|
return ipath;
|
|
}
|
|
if (ipath->next == NULL)
|
|
return ipath->next = new_ipath_node(pathname);
|
|
}
|
|
return first_incpath = new_ipath_node(pathname);
|
|
}
|
|
|
|
void set_listing(int on)
|
|
{
|
|
listena = on && produce_listing;
|
|
}
|
|
|
|
void set_list_title(char *p,int len)
|
|
{
|
|
listtitlecnt++;
|
|
listtitles=myrealloc(listtitles,listtitlecnt*sizeof(*listtitles));
|
|
listtitles[listtitlecnt-1]=mymalloc(len+1);
|
|
strncpy(listtitles[listtitlecnt-1],p,len);
|
|
listtitles[listtitlecnt-1][len]=0;
|
|
listtitlelines=myrealloc(listtitlelines,listtitlecnt*sizeof(*listtitlelines));
|
|
listtitlelines[listtitlecnt-1]=cur_src->line;
|
|
}
|
|
|
|
static void print_list_header(FILE *f,int cnt)
|
|
{
|
|
if(cnt%listlinesperpage==0){
|
|
if(cnt!=0&&listformfeed)
|
|
fprintf(f,"\f");
|
|
if(listtitlecnt>0){
|
|
int i,t;
|
|
for(i=0,t=-1;i<listtitlecnt;i++){
|
|
if(listtitlelines[i]<=cnt+listlinesperpage)
|
|
t=i;
|
|
}
|
|
if(t>=0){
|
|
int sp=(120-strlen(listtitles[t]))/2;
|
|
while(--sp)
|
|
fprintf(f," ");
|
|
fprintf(f,"%s\n",listtitles[t]);
|
|
}
|
|
cnt++;
|
|
}
|
|
fprintf(f,"Err Line Loc. S Object1 Object2 M Source\n");
|
|
}
|
|
}
|
|
|
|
#if VASM_CPU_OIL
|
|
void write_listing(char *listname)
|
|
{
|
|
FILE *f;
|
|
int nsecs,i,cnt=0,nl;
|
|
section *secp;
|
|
listing *p;
|
|
atom *a;
|
|
symbol *sym;
|
|
taddr pc;
|
|
char rel;
|
|
|
|
if(!(f=fopen(listname,"w"))){
|
|
general_error(13,listname);
|
|
return;
|
|
}
|
|
for(nsecs=0,secp=first_section;secp;secp=secp->next)
|
|
secp->idx=nsecs++;
|
|
for(p=first_listing;p;p=p->next){
|
|
if(!p->src||p->src->id!=0)
|
|
continue;
|
|
print_list_header(f,cnt++);
|
|
if(p->error!=0)
|
|
fprintf(f,"%04d ",p->error);
|
|
else
|
|
fprintf(f," ");
|
|
fprintf(f,"%4d ",p->line);
|
|
a=p->atom;
|
|
while(a&&a->type!=DATA&&a->next&&a->next->line==a->line&&a->next->src==a->src)
|
|
a=a->next;
|
|
if(a&&a->type==DATA){
|
|
int size=a->content.db->size;
|
|
char *dp=a->content.db->data;
|
|
pc=p->pc;
|
|
fprintf(f,"%05lX %d ",(unsigned long)pc,(int)(p->sec?p->sec->idx:0));
|
|
for(i=0;i<8;i++){
|
|
if(i==4)
|
|
fprintf(f," ");
|
|
if(i<size){
|
|
fprintf(f,"%02X",(unsigned char)*dp++);
|
|
pc++;
|
|
}else
|
|
fprintf(f," ");
|
|
/* append following atoms with align 1 directly */
|
|
if(i==size-1&&i<7&&a->next&&a->next->align<=a->align&&a->next->type==DATA&&a->next->line==a->line&&a->next->src==a->src){
|
|
a=a->next;
|
|
size+=a->content.db->size;
|
|
dp=a->content.db->data;
|
|
}
|
|
}
|
|
fprintf(f," ");
|
|
if(a->content.db->relocs){
|
|
symbol *s=((nreloc *)(a->content.db->relocs->reloc))->sym;
|
|
if(s->type==IMPORT)
|
|
rel='X';
|
|
else
|
|
rel='0'+p->sec->idx;
|
|
}else
|
|
rel='A';
|
|
fprintf(f,"%c ",rel);
|
|
}else
|
|
fprintf(f," ");
|
|
|
|
fprintf(f," %-.77s",p->txt);
|
|
|
|
/* bei laengeren Daten den Rest ueberspringen */
|
|
/* Block entfernen, wenn alles ausgegeben werden soll */
|
|
if(a&&a->type==DATA&&i<a->content.db->size){
|
|
pc+=a->content.db->size-i;
|
|
i=a->content.db->size;
|
|
}
|
|
|
|
/* restliche DATA-Zeilen, wenn noetig */
|
|
while(a){
|
|
if(a->type==DATA){
|
|
int size=a->content.db->size;
|
|
char *dp=a->content.db->data+i;
|
|
|
|
if(i<size){
|
|
for(;i<size;i++){
|
|
if((i&7)==0){
|
|
fprintf(f,"\n");
|
|
print_list_header(f,cnt++);
|
|
fprintf(f," %05lX %d ",(unsigned long)pc,(int)(p->sec?p->sec->idx:0));
|
|
}else if((i&3)==0)
|
|
fprintf(f," ");
|
|
fprintf(f,"%02X",(unsigned char)*dp++);
|
|
pc++;
|
|
/* append following atoms with align 1 directly */
|
|
if(i==size-1&&a->next&&a->next->align<=a->align&&a->next->type==DATA&&a->next->line==a->line&&a->next->src==a->src){
|
|
a=a->next;
|
|
size+=a->content.db->size;
|
|
dp=a->content.db->data;
|
|
}
|
|
}
|
|
i=8-(i&7);
|
|
if(i>=4)
|
|
fprintf(f," ");
|
|
while(i--){
|
|
fprintf(f," ");
|
|
}
|
|
fprintf(f," %c",rel);
|
|
}
|
|
i=0;
|
|
}
|
|
if(a->next&&a->next->line==a->line&&a->next->src==a->src){
|
|
a=a->next;
|
|
pc=pcalign(a,pc);
|
|
if(a->type==DATA&&a->content.db->relocs){
|
|
symbol *s=((nreloc *)(a->content.db->relocs->reloc))->sym;
|
|
if(s->type==IMPORT)
|
|
rel='X';
|
|
else
|
|
rel='0'+p->sec->idx;
|
|
}else
|
|
rel='A';
|
|
}else
|
|
a=0;
|
|
}
|
|
fprintf(f,"\n");
|
|
}
|
|
fprintf(f,"\n\nSections:\n");
|
|
for(secp=first_section;secp;secp=secp->next)
|
|
fprintf(f,"%d %s\n",(int)secp->idx,secp->name);
|
|
if(!listnosyms){
|
|
fprintf(f,"\n\nSymbols:\n");
|
|
{
|
|
symbol *last=0,*cur,*symo;
|
|
for(symo=first_symbol;symo;symo=symo->next){
|
|
cur=0;
|
|
for(sym=first_symbol;sym;sym=sym->next){
|
|
if(!last||stricmp(sym->name,last->name)>0)
|
|
if(!cur||stricmp(sym->name,cur->name)<0)
|
|
cur=sym;
|
|
}
|
|
if(cur){
|
|
print_symbol(f,cur);
|
|
fprintf(f,"\n");
|
|
last=cur;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if(errors==0)
|
|
fprintf(f,"\nThere have been no errors.\n");
|
|
else
|
|
fprintf(f,"\nThere have been %d errors!\n",errors);
|
|
fclose(f);
|
|
for(p=first_listing;p;){
|
|
listing *m=p->next;
|
|
myfree(p);
|
|
p=m;
|
|
}
|
|
}
|
|
#else
|
|
void write_listing(char *listname)
|
|
{
|
|
FILE *f;
|
|
int nsecs,i,maxsrc=0;
|
|
section *secp;
|
|
listing *p;
|
|
atom *a;
|
|
symbol *sym;
|
|
taddr pc;
|
|
|
|
if(!(f=fopen(listname,"w"))){
|
|
general_error(13,listname);
|
|
return;
|
|
}
|
|
for(nsecs=1,secp=first_section;secp;secp=secp->next)
|
|
secp->idx=nsecs++;
|
|
for(p=first_listing;p;p=p->next){
|
|
char err[6];
|
|
if(p->error!=0)
|
|
sprintf(err,"E%04d",p->error);
|
|
else
|
|
sprintf(err," ");
|
|
if(p->src&&p->src->id>maxsrc)
|
|
maxsrc=p->src->id;
|
|
fprintf(f,"F%02d:%04d %s %s",(int)(p->src?p->src->id:0),p->line,err,p->txt);
|
|
a=p->atom;
|
|
pc=p->pc;
|
|
while(a){
|
|
if(a->type==DATA){
|
|
int size=a->content.db->size;
|
|
for(i=0;i<size&&i<32;i++){
|
|
if((i&15)==0)
|
|
fprintf(f,"\n S%02d:%08lX: ",(int)(p->sec?p->sec->idx:0),(unsigned long)(pc));
|
|
fprintf(f," %02X",(unsigned char)a->content.db->data[i]);
|
|
pc++;
|
|
}
|
|
if(a->content.db->relocs)
|
|
fprintf(f," [R]");
|
|
}
|
|
if(a->next&&a->next->list==a->list){
|
|
a=a->next;
|
|
pc=pcalign(a,pc);
|
|
}else
|
|
a=0;
|
|
}
|
|
fprintf(f,"\n");
|
|
}
|
|
fprintf(f,"\n\nSections:\n");
|
|
for(secp=first_section;secp;secp=secp->next)
|
|
fprintf(f,"S%02d %s\n",(int)secp->idx,secp->name);
|
|
fprintf(f,"\n\nSources:\n");
|
|
for(i=0;i<=maxsrc;i++){
|
|
for(p=first_listing;p;p=p->next){
|
|
if(p->src&&p->src->id==i){
|
|
fprintf(f,"F%02d %s\n",i,p->src->name);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
fprintf(f,"\n\nSymbols:\n");
|
|
for(sym=first_symbol;sym;sym=sym->next){
|
|
print_symbol(f,sym);
|
|
fprintf(f,"\n");
|
|
}
|
|
if(errors==0)
|
|
fprintf(f,"\nThere have been no errors.\n");
|
|
else
|
|
fprintf(f,"\nThere have been %d errors!\n",errors);
|
|
fclose(f);
|
|
for(p=first_listing;p;){
|
|
listing *m=p->next;
|
|
myfree(p);
|
|
p=m;
|
|
}
|
|
}
|
|
#endif
|