Initial import from FreeBSD RELENG_4:
[dragonfly.git] / gnu / usr.bin / as / as.c
1 /* as.c - GAS main program.
2    Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc.
3
4    This file is part of GAS, the GNU Assembler.
5
6    GAS is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2, or (at your option)
9    any later version.
10
11    GAS is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with GAS; see the file COPYING.  If not, write to
18    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20 /*
21  * Main program for AS; a 32-bit assembler of GNU.
22  * Understands command arguments.
23  * Has a few routines that don't fit in other modules because they
24  * are shared.
25  *
26  *
27  *                      bugs
28  *
29  * : initialisers
30  *      Since no-one else says they will support them in future: I
31  * don't support them now.
32  *
33  */
34 #ifndef lint
35 static char rcsid[] = "$FreeBSD: src/gnu/usr.bin/as/as.c,v 1.7 1999/08/27 23:34:11 peter Exp $";
36 #endif
37
38 #include <stdio.h>
39 #include <string.h>
40
41 #ifdef _POSIX_SOURCE
42 #include <sys/types.h>  /* For pid_t in signal.h */
43 #endif
44 #include <signal.h>
45
46 #define COMMON
47
48 #include "as.h"
49 #include "subsegs.h"
50 #if __STDC__ == 1
51
52 /* This prototype for got_sig() is ansi.  If you want
53    anything else, then your compiler is lying to you when
54    it says that it is __STDC__.  If you want to change it,
55    #ifdef protect it from those of us with real ansi
56    compilers. */
57
58 #define SIGTY void
59
60 static void got_sig(int sig);
61 static char *stralloc(char *str);
62 static void perform_an_assembly_pass(int argc, char **argv);
63
64 #else /* __STDC__ */
65
66 #ifndef SIGTY
67 #define SIGTY int
68 #endif
69
70 static SIGTY got_sig();
71 static char *stralloc();        /* Make a (safe) copy of a string. */
72 static void perform_an_assembly_pass();
73
74 #endif /* not __STDC__ */
75
76 #ifdef DONTDEF
77 static char * gdb_symbol_file_name;
78 long gdb_begin();
79 #endif
80
81 int listing; /* true if a listing is wanted */
82
83 char *myname;           /* argv[0] */
84 extern const char version_string[];
85 \f
86 int main(argc,argv)
87 int argc;
88 char **argv;
89 {
90         int work_argc;  /* variable copy of argc */
91         char **work_argv;       /* variable copy of argv */
92         char *arg;              /* an arg to program */
93         char a;         /* an arg flag (after -) */
94         static const int sig[] = { SIGHUP, SIGINT, SIGPIPE, SIGTERM, 0};
95
96         for (a=0;sig[a] != 0;a++)
97             if (signal(sig[a], SIG_IGN) != SIG_IGN)
98                 signal(sig[a], got_sig);
99
100         myname=argv[0];
101         memset(flagseen, '\0', sizeof(flagseen)); /* aint seen nothing yet */
102 #ifndef OBJ_DEFAULT_OUTPUT_FILE_NAME
103 #define OBJ_DEFAULT_OUTPUT_FILE_NAME "a.out"
104 #endif /* OBJ_DEFAULT_OUTPUT_FILE_NAME */
105         out_file_name = OBJ_DEFAULT_OUTPUT_FILE_NAME;
106
107         symbol_begin();         /* symbols.c */
108         subsegs_begin();                /* subsegs.c */
109         read_begin();                   /* read.c */
110         md_begin();                     /* MACHINE.c */
111         input_scrub_begin();            /* input_scrub.c */
112 #ifdef DONTDEF
113         gdb_symbol_file_name = 0;
114 #endif
115         /*
116          * Parse arguments, but we are only interested in flags.
117          * When we find a flag, we process it then make it's argv[] NULL.
118          * This helps any future argv[] scanners avoid what we processed.
119          * Since it is easy to do here we interpret the special arg "-"
120          * to mean "use stdin" and we set that argv[] pointing to "".
121          * After we have munged argv[], the only things left are source file
122          * name(s) and ""(s) denoting stdin. These file names are used
123          * (perhaps more than once) later.
124          */
125         /* FIXME-SOMEDAY this should use getopt. */
126         work_argc = argc-1;             /* don't count argv[0] */
127         work_argv = argv+1;             /* skip argv[0] */
128         for (;work_argc--;work_argv++) {
129                 arg = * work_argv;      /* work_argv points to this argument */
130
131                 if (*arg != '-')                /* Filename. We need it later. */
132                     continue;   /* Keep scanning args looking for flags. */
133                 if (arg[1] == '-' && arg[2] == 0) {
134                         /* "--" as an argument means read STDIN */
135                         /* on this scan, we don't want to think about filenames */
136                         * work_argv = "";       /* Code that means 'use stdin'. */
137                         continue;
138                 }
139                 /* This better be a switch. */
140                 arg ++;         /*->letter. */
141
142                 while ((a = * arg) != '\0')  {/* scan all the 1-char flags */
143                         arg ++; /* arg->after letter. */
144                         a &= 0x7F;      /* ascii only please */
145                         /* if (flagseen[a])
146                            as_tsktsk("%s: Flag option - %c has already been seen.", myname, a); */
147                         flagseen[a] = 1;
148                         switch (a) {
149
150                         case 'a':
151                                 {
152                                         int loop =1;
153
154                                         while (loop) {
155                                                 switch (*arg)
156                                                     {
157                                                     case 'l':
158                                                             listing |= LISTING_LISTING;
159                                                             arg++;
160                                                             break;
161                                                     case 's':
162                                                             listing |= LISTING_SYMBOLS;
163                                                             arg++;
164                                                             break;
165                                                     case 'h':
166                                                             listing |= LISTING_HLL;
167                                                             arg++;
168                                                             break;
169
170                                                     case 'n':
171                                                             listing |= LISTING_NOFORM;
172                                                             arg++;
173                                                             break;
174                                                     case 'd':
175                                                             listing |= LISTING_NODEBUG;
176                                                             arg++;
177                                                             break;
178                                                     default:
179                                                             if (!listing)
180                                                                 listing= LISTING_DEFAULT;
181                                                             loop = 0;
182                                                             break;
183                                                     }
184                                         }
185                                 }
186
187                                 break;
188
189
190                         case 'f':
191                                 break;  /* -f means fast - no need for "app" preprocessor. */
192
193                         case 'D':
194                                 /* DEBUG is implemented: it debugs different */
195                                 /* things to other people's assemblers. */
196                                 break;
197
198 #ifdef DONTDEF
199                         case 'G':       /* GNU AS switch: include gdbsyms. */
200                                 if (*arg)       /* Rest of argument is file-name. */
201                                     gdb_symbol_file_name = stralloc (arg);
202                                 else if (work_argc) {   /* Next argument is file-name. */
203                                         work_argc --;
204                                         * work_argv = NULL; /* Not a source file-name. */
205                                         gdb_symbol_file_name = * ++ work_argv;
206                                 } else
207                                     as_warn("%s: I expected a filename after -G", myname);
208                                 arg = "";       /* Finished with this arg. */
209                                 break;
210 #endif
211
212                         case 'I': { /* Include file directory */
213
214                                 char *temp = NULL;
215                                 if (*arg)
216                                     temp = stralloc (arg);
217                                 else if (work_argc) {
218                                         * work_argv = NULL;
219                                         work_argc--;
220                                         temp = * ++ work_argv;
221                                 } else
222                                     as_warn("%s: I expected a filename after -I", myname);
223                                 add_include_dir (temp);
224                                 arg = "";       /* Finished with this arg. */
225                                 break;
226                         }
227
228                         case 'L': /* -L means keep L* symbols */
229                                 break;
230
231                         case 'o':
232                                 if (*arg)       /* Rest of argument is object file-name. */
233                                     out_file_name = stralloc (arg);
234                                 else if (work_argc) {   /* Want next arg for a file-name. */
235                                         * work_argv = NULL; /* This is not a file-name. */
236                                         work_argc--;
237                                         out_file_name = * ++ work_argv;
238                                 } else
239                                     as_warn("%s: I expected a filename after -o. \"%s\" assumed.", myname, out_file_name);
240                                 arg = "";       /* Finished with this arg. */
241                                 break;
242
243                         case 'R':
244                                 /* -R means put data into text segment */
245                                 break;
246
247                         case 'v':
248 #ifdef  OBJ_VMS
249                                 {
250                                         extern char *compiler_version_string;
251                                         compiler_version_string = arg;
252                                 }
253 #else /* not OBJ_VMS */
254                                 fprintf(stderr,version_string);
255                                 if (*arg && strcmp(arg,"ersion"))
256                                     as_warn("Unknown -v option ignored");
257 #endif /* not OBJ_VMS */
258                                 while (*arg) arg++;     /* Skip the rest */
259                                 break;
260
261                         case 'W':
262                                 /* -W means don't warn about things */
263                         case 'X':
264                                 /* -X means treat warnings as errors */
265                         case 'Z':
266                                 /* -Z means attempt to generate object file even after errors. */
267                                 break;
268
269                         default:
270                                 --arg;
271                                 if (md_parse_option(&arg,&work_argc,&work_argv) == 0)
272                                     as_warn("%s: I don't understand '%c' flag.", myname, a);
273                                 if (arg && *arg)
274                                     arg++;
275                                 break;
276                         }
277                 }
278                 /*
279                  * We have just processed a "-..." arg, which was not a
280                  * file-name. Smash it so the
281                  * things that look for filenames won't ever see it.
282                  *
283                  * Whatever work_argv points to, it has already been used
284                  * as part of a flag, so DON'T re-use it as a filename.
285                  */
286                 *work_argv = NULL; /* NULL means 'not a file-name' */
287         }
288 #ifdef PIC
289         if (flagseen['K'] || flagseen['k'])
290                 picmode = 1;
291 #endif
292 #ifdef DONTDEF
293         if (gdb_begin(gdb_symbol_file_name) == 0)
294             flagseen['G'] = 0;  /* Don't do any gdbsym stuff. */
295 #endif
296         /* Here with flags set up in flagseen[]. */
297
298         perform_an_assembly_pass(argc,argv); /* Assemble it. */
299 #ifdef TC_I960
300         brtab_emit();
301 #endif
302         if (seen_at_least_1_file()
303             && !((had_warnings() && flagseen['Z'])
304                  || had_errors() > 0)) {
305                 write_object_file(); /* relax() addresses then emit object file */
306         } /* we also check in write_object_file() just before emit. */
307
308         input_scrub_end();
309         md_end();                       /* MACHINE.c */
310
311 #ifndef NO_LISTING
312         listing_print("");
313 #endif
314
315 #ifndef HO_VMS
316         return((had_warnings() && flagseen['Z'])
317                || had_errors() > 0);                    /* WIN */
318 #else   /* HO_VMS */
319         return(!((had_warnings() && flagseen['Z'])
320                  || had_errors() > 0));                 /* WIN */
321 #endif  /* HO_VMS */
322
323 } /* main() */
324
325 \f
326 /*                      perform_an_assembly_pass()
327  *
328  * Here to attempt 1 pass over each input file.
329  * We scan argv[*] looking for filenames or exactly "" which is
330  * shorthand for stdin. Any argv that is NULL is not a file-name.
331  * We set need_pass_2 TRUE if, after this, we still have unresolved
332  * expressions of the form (unknown value)+-(unknown value).
333  *
334  * Note the un*x semantics: there is only 1 logical input file, but it
335  * may be a catenation of many 'physical' input files.
336  */
337 static void perform_an_assembly_pass(argc, argv)
338 int argc;
339 char **argv;
340 {
341         int saw_a_file = 0;
342         need_pass_2             = 0;
343
344 #ifdef MANY_SEGMENTS
345         unsigned int i;
346
347         for (i= SEG_E0; i < SEG_UNKNOWN; i++)
348             {
349                     segment_info[i].fix_root = 0;
350             }
351         /* Create the three fixed ones */
352         subseg_new (SEG_E0, 0);
353         subseg_new (SEG_E1, 0);
354         subseg_new (SEG_E2, 0);
355         strcpy(segment_info[SEG_E0].scnhdr.s_name,".text");
356         strcpy(segment_info[SEG_E1].scnhdr.s_name,".data");
357         strcpy(segment_info[SEG_E2].scnhdr.s_name,".bss");
358
359         subseg_new (SEG_E0, 0);
360 #else /* not MANY_SEGMENTS */
361         text_fix_root           = NULL;
362         data_fix_root           = NULL;
363         bss_fix_root            = NULL;
364
365         subseg_new (SEG_TEXT, 0);
366 #endif /* not MANY_SEGMENTS */
367
368         argv++; /* skip argv[0] */
369         argc--; /* skip argv[0] */
370         while (argc--) {
371                 if (*argv) { /* Is it a file-name argument? */
372                         saw_a_file++;
373                         /* argv->"" if stdin desired, else->filename */
374                         read_a_source_file(*argv);
375                 }
376                 argv++; /* completed that argv */
377         }
378         if (!saw_a_file)
379             read_a_source_file("");
380 } /* perform_an_assembly_pass() */
381 \f
382 /*
383  *                      stralloc()
384  *
385  * Allocate memory for a new copy of a string. Copy the string.
386  * Return the address of the new string. Die if there is any error.
387  */
388
389 static char *
390     stralloc (str)
391 char *  str;
392 {
393         register char * retval;
394         register long len;
395
396         len = strlen (str) + 1;
397         retval = xmalloc (len);
398         (void) strcpy(retval, str);
399         return(retval);
400 }
401 \f
402 #ifdef comment
403 static void lose() {
404         as_fatal("%s: 2nd pass not implemented - get your code from random(3)", myname);
405         return;
406 } /* lose() */
407 #endif /* comment */
408
409 static SIGTY
410     got_sig(sig)
411 int sig;
412 {
413         static here_before = 0;
414
415         as_bad("Interrupted by signal %d", sig);
416         if (here_before++)
417             exit(1);
418         return((SIGTY) 0);
419 }
420
421 /*
422  * Local Variables:
423  * comment-column: 0
424  * fill-column: 131
425  * End:
426  */
427
428 /* end of as.c */