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.
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
;
31 #if defined(__OPENSTEP__) || defined(__HERA__) || \
32 defined(__GONZO_BUNSEN_BEAKER__) || defined(__KODIAK__)
35 "../libexec/gcc/darwin/";
37 const char *LOCALLIB
=
38 #if defined(__OPENSTEP__) || defined(__HERA__) || \
39 defined(__GONZO_BUNSEN_BEAKER__) || defined(__KODIAK__)
42 "../local/libexec/gcc/darwin/";
44 const char *AS
= "/as";
45 const char *LLVM_MC
= "llvm-mc";
48 uint32_t count
, verbose
, run_llvm_mc
;
49 char *p
, c
, *arch_name
, *as
, *as_local
;
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
;
61 oflag_specified
= FALSE
;
63 * Construct the prefix to the assembler driver.
67 i
= _NSGetExecutablePath(p
, &bufsize
);
69 p
= allocate(bufsize
);
70 _NSGetExecutablePath(p
, &bufsize
);
72 prefix
= realpath(p
, resolved_name
);
74 system_fatal("realpath(3) for %s failed", p
);
75 p
= rindex(prefix
, '/');
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.
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 */
125 if(strcmp(p
, "arch") == 0){
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];
134 /* fall through for non "-arch" */
142 /* just recognize it, do nothing */
145 if(strcmp(p
, "llvm-mc") == 0)
147 /* also just recognize 'l' and do nothing */
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
);
167 llvm_mc_argv
= allocate(argc
+ 3);
168 llvm_mc_argv
[0] = as
;
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
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
];
188 * Add -filetype=obj or llvm-mc will write to stdout.
190 llvm_mc_argv
[j
] = "-filetype=obj";
193 * llvm-mc requires a "-o a.out" if not -o is specified.
195 if(oflag_specified
== FALSE
){
196 llvm_mc_argv
[j
] = "-o";
198 llvm_mc_argv
[j
] = "a.out";
201 llvm_mc_argv
[j
] = NULL
;
202 if(execute(llvm_mc_argv
, verbose
))
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
)){
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
;
226 fatal("unknown host architecture (can't determine which "
227 "assembler to run)");
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){
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){
250 if(execute(argv
, verbose
))
255 as_local
= makestr(prefix
, LOCALLIB
, arch_name
, AS
, NULL
);
256 if(access(as_local
, F_OK
) == 0){
258 if(execute(argv
, verbose
))
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();
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){
272 printf("Installed assemblers are:\n");
273 printf("%s for architecture %s\n", as
, arch_flags
[i
].name
);
277 as_local
= makestr(prefix
, LOCALLIB
, arch_flags
[i
].name
,
279 if(access(as_local
, F_OK
) == 0){
281 printf("Installed assemblers are:\n");
282 printf("%s for architecture %s\n", as_local
,
289 printf("%s: no assemblers installed\n", progname
);