home *** CD-ROM | disk | FTP | other *** search
- /* $VER: pasm main.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
- * Allow more than two assembler passes, as required for
- * optimizations.
- * Option -O (output format) was renamed to -F. New option -O for
- * enabling optimizations.
- * Output format 3 is ADOS (like EHF, but doesn't use HUNK_PPC_CODE).
- * v0.6 (30.10.97) phx
- * Options to disable warnings for optional, 64-bit and super-
- * visor instructions: -mo, -m64, -ms.
- * v0.5 (12.10.97) phx
- * Option -D defines symbols. If an '=' is missing, a default
- * value of '1' will be assigned. Assignment of symbols, which
- * are defined later in the source, is also allowed.
- * v0.4 (05.07.97) phx
- * Program returns EXIT_FAILURE if an error occurs.
- * -V prints only version and build string and no instructions.
- * Base address for absolute code may be set with -B option.
- * EHF support.
- * New option -I to specify some include paths.
- * Option -x automatically declares unknown symbols as
- * externally defined.
- * v0.2 (25.03.97) phx
- * Writes ELF object for 32-bit PowerPC big-endian. Either absolute
- * or ELF output format may be selected. ELF is default for all
- * currently supported platforms. PPCasm supports nine different
- * relocation types (there are much more...).
- * Compiles and works also under NetBSD/amiga (68k).
- * Changed function declaration to 'new style' in all sources
- * (to avoid problems with '...' for example).
- * Supports multiple output formats. Currently Absolute and ELF.
- * v0.1 (11.03.97) phx
- * First test version with all PowerPC instructions and most
- * important directives. Only raw, absolute output.
- * v0.0 (14.02.97) phx
- * File created. Project started.
- */
-
-
- #define MAIN_C
- #include "ppcasm.h"
-
-
- struct GlobalVars gvars;
-
-
- void cleanup(struct GlobalVars *);
-
- static char *default_destname(struct GlobalVars *);
- static void reset_sections(struct GlobalVars *);
- static char *get_option_arg(int,char *[],int *);
- static void write_object(struct GlobalVars *);
-
-
-
- main(int argc,char *argv[])
- {
- struct GlobalVars *gv = &gvars;
- int i,j;
- char *buf;
- char *stdassgn = "1"; /* default assignment for user definitions */
- struct UserDefine *udn;
-
- /* initialize and set default values */
- memset(gv,0,sizeof(struct GlobalVars));
- gv->maxerrors = DEF_MAXERRORS;
- gv->output = OFMT_DEFAULT; /* default output format */
- initlist(&gv->sourcelist);
- initlist(&gv->sectionlist);
- initlist(&gv->userdeflist);
-
- if (argc<2 || (argc==2 && *argv[1]=='?')) {
- show_usage();
- exit(EXIT_SUCCESS);
- }
- for (i=1; i<argc; i++) {
- if (*argv[i] == '-') {
- /* option detected */
- switch (argv[i][1]) {
-
- case 'V': /* show version */
- show_version();
- exit(EXIT_SUCCESS);
-
- case 'o': /* set output file */
- if (!(gv->dest_name = get_option_arg(argc,argv,&i)))
- error(3); /* missing output file name */
- break;
-
- case 'w': /* suppress warnings */
- gv->dontwarn = TRUE;
- break;
-
- case 'x': /* auto extern */
- gv->autoextern = TRUE;
- break;
-
- case 'R': /* don't predefine register symbols, etc. */
- gv->noregsymbols = TRUE;
- break;
-
- case 'X': /* no extended mnemonics */
- gv->noextmnemo = TRUE;
- break;
-
- case 'F': /* set output format (0=abs, 1=elf, 2=ehf, ... ) */
- if (buf = get_option_arg(argc,argv,&i)) {
- if ((j = atoi(buf)) > OFMT_LAST)
- error(49,j); /* unknown output format */
- else
- gv->output = j;
- }
- else
- error(48,'F'); /* option -F: argument expected */
- break;
-
- case 'O': /* set optimization level (0=none, ...) */
- if (buf = get_option_arg(argc,argv,&i))
- gv->opt = (uint32)atoi(buf);
- else
- error(48,'O'); /* option -O: argument expected */
- break;
-
- case 'I': /* add include path */
- for (j=0; j<MAX_INCPATHS; j++) {
- if (gv->incpaths[j] == NULL) {
- if (!(gv->incpaths[j] = get_option_arg(argc,argv,&i)))
- error(48,'I'); /* option -I: argument expected */
- break;
- }
- }
- if (j >= MAX_INCPATHS) /* path was ignored */
- error(51,MAX_INCPATHS,get_option_arg(argc,argv,&i));
- break;
-
- case 'B': /* base address for absolute code */
- if (buf = get_option_arg(argc,argv,&i)) {
- if (!(sscanf(buf,"%li",(long *)&gv->absbase)))
- error(54,'B'); /* option -B: integer expected */
- }
- else
- error(48,'B'); /* option -B: argument expected */
- break;
-
- case 'D': /* define a symbol */
- if (buf = get_option_arg(argc,argv,&i)) {
- buf = getsymbol(gv,buf);
- if (*gv->strbuf) {
- buf = skipspaces(buf);
- if (*buf == '=')
- buf = skipspaces(++buf);
- else
- buf = stdassgn;
- udn = alloc(sizeof(struct UserDefine));
- udn->line = alloc(8 + strlen(gv->strbuf) + strlen(buf));
- sprintf(udn->line,".set %s,%s\n",gv->strbuf,buf);
- addtail(&gv->userdeflist,&udn->n);
- }
- else
- error(56,'D'); /* option -D: symbol name expected */
- }
- else
- error(48,'D'); /* option -D: argument expected */
- break;
-
- case 'm': /* -m set assembler mode */
- if (buf = get_option_arg(argc,argv,&i)) {
- if (!strcmp(buf,"64")) {
- gv->sixtyfourmode = TRUE;
- break;
- }
- else if (*buf == 'o') {
- gv->optinstrmode = TRUE;
- break;
- }
- else if (*buf == 's') {
- gv->supermode = TRUE;
- break;
- }
- }
- error(57,buf); /* Unknown assembler mode -mX */
- break;
-
- default:
- printf("Unknown option -%c ignored.\n",argv[i][1]);
- break;
- }
- }
- else {
- /* source file name */
- if (gv->source_name)
- error(4); /* multiple source file names detected */
- gv->source_name = argv[i];
- }
- }
- if (!gv->source_name)
- error(2); /* missing source file name */
-
- if (!gv->dest_name)
- gv->dest_name = default_destname(gv);
-
- /* initialization */
- init_hashtables(gv);
-
- /* assemble */
- exec_pass1(gv);
-
- for (;;) {
- gv->anotherpass = FALSE;
- exec_pass2(gv);
- if (!gv->anotherpass)
- break;
- /* another pass is required! */
- reset_sections(gv);
- }
-
- /* write output file */
- write_object(gv);
- cleanup(gv);
- }
-
-
- static void reset_sections(struct GlobalVars *gv)
- /* free section contents, all xrefs and relocations */
- {
- struct Section *nexts,*sec=(struct Section *)gv->sectionlist.first;
- struct node *n;
-
- while (nexts = (struct Section *)sec->n.next) {
- while (n = remhead(&sec->reloclist))
- free(n);
- while (n = remhead(&sec->xreflist))
- free(n);
- if (!(sec->flags & SF_UNINITIALIZED) && sec->contents) {
- free(sec->contents);
- sec->data = sec->contents = NULL;
- }
- sec = nexts;
- }
- }
-
-
- static char *default_destname(struct GlobalVars *gv)
- /* make default output file name from source file name */
- {
- char dname[STRBUFSIZE];
- int i;
-
- strncpy(dname,gv->source_name,STRBUFSIZE-1);
- i = strlen(dname);
- while (i--) {
- if (dname[i] == '.') { /* replace old extension by ".o" */
- dname[i] = 0;
- break;
- }
- }
- strcat(dname,".o");
- return (allocstring(dname));
- }
-
-
- static char *get_option_arg(int argc,char *argv[],int *i)
- /* get pointer to the string, which either directly follows the option
- character or is stored in the next argument */
- {
- if (!argv[*i][2])
- if (++*i<argc)
- return (argv[*i]);
- else
- return NULL;
- else
- return (&argv[*i][2]);
- }
-
-
- static void write_object(struct GlobalVars *gv)
- /* creates the object file */
- {
- switch(gv->output) {
- case OFMT_ABSOLUTE:
- output_absolute(gv);
- break;
- case OFMT_ELF:
- output_elf32msb(gv);
- break;
- case OFMT_EHF:
- case OFMT_ADOS:
- output_ehf(gv);
- break;
- }
- }
-
-
- void cleanup(struct GlobalVars *gv)
- {
- exit(gv->returncode);
- }
-