795
[darwin-xtools.git] / cctools / as / driver.c
blobe7258c8fb96ca4e29293ea3a8d685de4689c7112
1 /*
2 * The assembler driver that lives in /bin/as and runs the assembler for the
3 * "-arch <arch_flag>" (if given) in /usr/libexec/gcc/darwin/<arch_flag>/as or
4 * in /usr/local/libexec/gcc/darwin/<arch_flag>/as. Or runs the assembler for
5 * the host architecture as returned by get_arch_from_host(). The driver only
6 * checks to make sure their are not multiple arch_flags and then passes all
7 * flags to the assembler it will run.
8 */
9 #include "stdio.h"
10 #include "stdlib.h"
11 #include "string.h"
12 #include "libc.h"
13 #include <sys/file.h>
14 #include <mach/mach.h>
15 #include "stuff/arch.h"
16 #include "stuff/errors.h"
17 #include "stuff/execute.h"
18 #include "stuff/allocate.h"
19 #include <mach-o/dyld.h>
21 /* used by error calls (exported) */
22 char *progname = NULL;
24 int
25 main(
26 int argc,
27 char **argv,
28 char **envp)
30 const char *LIB =
31 #if defined(__OPENSTEP__) || defined(__HERA__) || \
32 defined(__GONZO_BUNSEN_BEAKER__) || defined(__KODIAK__)
33 "../libexec/";
34 #else
35 "../libexec/gcc/darwin/";
36 #endif
37 const char *LOCALLIB =
38 #if defined(__OPENSTEP__) || defined(__HERA__) || \
39 defined(__GONZO_BUNSEN_BEAKER__) || defined(__KODIAK__)
40 "../local/libexec/";
41 #else
42 "../local/libexec/gcc/darwin/";
43 #endif
44 const char *AS = "/as";
45 const char *LLVM_MC = "llvm-mc";
47 int i, j;
48 uint32_t count, verbose, run_llvm_mc;
49 char *p, c, *arch_name, *as, *as_local;
50 char **llvm_mc_argv;
51 char *prefix, buf[MAXPATHLEN], resolved_name[PATH_MAX];
52 unsigned long bufsize;
53 struct arch_flag arch_flag;
54 const struct arch_flag *arch_flags, *family_arch_flag;
55 enum bool oflag_specified;
57 progname = argv[0];
58 arch_name = NULL;
59 verbose = 0;
60 run_llvm_mc = 0;
61 oflag_specified = FALSE;
63 * Construct the prefix to the assembler driver.
65 bufsize = MAXPATHLEN;
66 p = buf;
67 i = _NSGetExecutablePath(p, &bufsize);
68 if(i == -1){
69 p = allocate(bufsize);
70 _NSGetExecutablePath(p, &bufsize);
72 prefix = realpath(p, resolved_name);
73 if(realpath == NULL)
74 system_fatal("realpath(3) for %s failed", p);
75 p = rindex(prefix, '/');
76 if(p != NULL)
77 p[1] = '\0';
79 * Process the assembler flags exactly like the assembler would (except
80 * let the assembler complain about multiple flags, bad combinations of
81 * flags, unknown single letter flags and the like). The main thing
82 * here is to parse out the "-arch <arch_flag>" and to do so the
83 * multiple argument and multiple character flags need to be known how
84 * to be stepped over correctly.
86 for(i = 1; i < argc; i++){
88 * The assembler flags start with '-' except that "--" is recognized
89 * as assemble from stdin and that flag "--" is not allowed to be
90 * grouped with other flags (so "-a-" is not the same as "-a --").
92 if(argv[i][0] == '-' &&
93 !(argv[i][1] == '-' && argv[i][2] == '0')){
95 * the assembler allows single letter flags to be grouped
96 * together so "-abc" is the same as "-a -b -c". So that
97 * logic must be followed here.
99 for(p = &(argv[i][1]); (c = *p); p++){
101 * The assembler simply ignores the high bit of flag
102 * characters and not treat them as different characters
103 * as they are (but the argument following the flag
104 * character is not treated this way). So it's done
105 * here as well to match it.
107 c &= 0x7F;
108 switch(c){
110 * Flags that take a single argument. The argument is the
111 * rest of the current argument if there is any or the it is
112 * the next argument. Again errors like missing arguments
113 * are not handled here but left to the assembler.
115 case 'o': /* -o name */
116 oflag_specified = TRUE;
117 case 'I': /* -I directory */
118 case 'm': /* -mc68000, -mc68010 and mc68020 */
119 case 'N': /* -NEXTSTEP-deployment-target */
120 if(p[1] == '\0')
121 i++;
122 break;
124 case 'a':
125 if(strcmp(p, "arch") == 0){
126 if(i + 1 >= argc)
127 fatal("missing argument to %s option", argv[i]);
128 if(arch_name != NULL)
129 fatal("more than one %s option (not allowed, "
130 "use cc(1) instead)", argv[i]);
131 arch_name = argv[i+1];
132 break;
134 /* fall through for non "-arch" */
135 case 'f':
136 case 'k':
137 case 'g':
138 case 'v':
139 case 'W':
140 case 'L':
141 default:
142 /* just recognize it, do nothing */
143 break;
144 case 'l':
145 if(strcmp(p, "llvm-mc") == 0)
146 run_llvm_mc = i;
147 /* also just recognize 'l' and do nothing */
148 break;
149 case 'V':
150 verbose = 1;
151 break;
158 * If the -llvm-mc flag was specified then run llvm-mc from the same
159 * directory as the driver.
161 if(run_llvm_mc != 0){
162 as = makestr(prefix, LLVM_MC, NULL);
163 if(access(as, F_OK) != 0){
164 printf("%s: assembler (%s) not installed\n", progname, as);
165 exit(1);
167 llvm_mc_argv = allocate(argc + 3);
168 llvm_mc_argv[0] = as;
169 j = 1;
170 for(i = 1; i < argc; i++){
172 * Do not pass -llvm-mc
174 if(i != run_llvm_mc){
176 * Do not pass command line argument that are Unknown to
177 * to llvm-mc.
179 if(strcmp(argv[i], "-v") != 0 &&
180 strcmp(argv[i], "-V") != 0 &&
181 strcmp(argv[i], "-force_cpusubtype_ALL") != 0){
182 llvm_mc_argv[j] = argv[i];
183 j++;
188 * Add -filetype=obj or llvm-mc will write to stdout.
190 llvm_mc_argv[j] = "-filetype=obj";
191 j++;
193 * llvm-mc requires a "-o a.out" if not -o is specified.
195 if(oflag_specified == FALSE){
196 llvm_mc_argv[j] = "-o";
197 j++;
198 llvm_mc_argv[j] = "a.out";
199 j++;
201 llvm_mc_argv[j] = NULL;
202 if(execute(llvm_mc_argv, verbose))
203 exit(0);
204 else
205 exit(1);
209 * Construct the name of the assembler to run from the given -arch
210 * <arch_flag> or if none then from the value returned from
211 * get_arch_from_host().
213 if(arch_name == NULL){
214 if(get_arch_from_host(&arch_flag, NULL)){
215 #if __LP64__
217 * If runing as a 64-bit binary and on an Intel x86 host
218 * default to the 64-bit assember.
220 if(arch_flag.cputype == CPU_TYPE_I386)
221 arch_flag = *get_arch_family_from_cputype(CPU_TYPE_X86_64);
222 #endif /* __LP64__ */
223 arch_name = arch_flag.name;
225 else
226 fatal("unknown host architecture (can't determine which "
227 "assembler to run)");
229 else{
231 * Convert a possible machine specific architecture name to a
232 * family name to base the name of the assembler to run.
234 if(get_arch_from_flag(arch_name, &arch_flag) != 0){
235 family_arch_flag =
236 get_arch_family_from_cputype(arch_flag.cputype);
237 if(family_arch_flag != NULL)
238 arch_name = (char *)(family_arch_flag->name);
243 as = makestr(prefix, LIB, arch_name, AS, NULL);
246 * If this assembler exist try to run it else print an error message.
248 if(access(as, F_OK) == 0){
249 argv[0] = as;
250 if(execute(argv, verbose))
251 exit(0);
252 else
253 exit(1);
255 as_local = makestr(prefix, LOCALLIB, arch_name, AS, NULL);
256 if(access(as_local, F_OK) == 0){
257 argv[0] = as_local;
258 if(execute(argv, verbose))
259 exit(0);
260 else
261 exit(1);
263 else{
264 printf("%s: assembler (%s or %s) for architecture %s not "
265 "installed\n", progname, as, as_local, arch_name);
266 arch_flags = get_arch_flags();
267 count = 0;
268 for(i = 0; arch_flags[i].name != NULL; i++){
269 as = makestr(prefix, LIB, arch_flags[i].name, AS, NULL);
270 if(access(as, F_OK) == 0){
271 if(count == 0)
272 printf("Installed assemblers are:\n");
273 printf("%s for architecture %s\n", as, arch_flags[i].name);
274 count++;
276 else{
277 as_local = makestr(prefix, LOCALLIB, arch_flags[i].name,
278 AS, NULL);
279 if(access(as_local, F_OK) == 0){
280 if(count == 0)
281 printf("Installed assemblers are:\n");
282 printf("%s for architecture %s\n", as_local,
283 arch_flags[i].name);
284 count++;
288 if(count == 0)
289 printf("%s: no assemblers installed\n", progname);
290 exit(1);
292 return(0);