comparison gen/toobj.cpp @ 676:1f0a78174598

Make ldc call gcc to assemble.
author Christian Kamm <kamm incasoftware de>
date Sat, 11 Oct 2008 20:00:36 +0200
parents bfe5229f9d8e
children 075c1272a01d
comparison
equal deleted inserted replaced
675:bfe5229f9d8e 676:1f0a78174598
18 #include "llvm/Target/TargetMachine.h" 18 #include "llvm/Target/TargetMachine.h"
19 #include "llvm/Target/TargetMachineRegistry.h" 19 #include "llvm/Target/TargetMachineRegistry.h"
20 #include "llvm/Module.h" 20 #include "llvm/Module.h"
21 #include "llvm/ModuleProvider.h" 21 #include "llvm/ModuleProvider.h"
22 #include "llvm/PassManager.h" 22 #include "llvm/PassManager.h"
23 #include "llvm/System/Program.h"
23 #include "llvm/System/Path.h" 24 #include "llvm/System/Path.h"
24 #include "llvm/Support/raw_ostream.h" 25 #include "llvm/Support/raw_ostream.h"
25 26
26 #include "mars.h" 27 #include "mars.h"
27 #include "module.h" 28 #include "module.h"
56 // in gen/optimize.cpp 57 // in gen/optimize.cpp
57 void ldc_optimize_module(llvm::Module* m, char lvl, bool doinline); 58 void ldc_optimize_module(llvm::Module* m, char lvl, bool doinline);
58 59
59 // fwd decl 60 // fwd decl
60 void write_asm_to_file(llvm::Module& m, llvm::raw_fd_ostream& Out); 61 void write_asm_to_file(llvm::Module& m, llvm::raw_fd_ostream& Out);
62 void assemble(const llvm::sys::Path& asmpath, const llvm::sys::Path& objpath, char** envp);
61 63
62 ////////////////////////////////////////////////////////////////////////////////////////// 64 //////////////////////////////////////////////////////////////////////////////////////////
63 65
64 void Module::genobjfile(int multiobj) 66 void Module::genobjfile(int multiobj, char** envp)
65 { 67 {
66 bool logenabled = Logger::enabled(); 68 bool logenabled = Logger::enabled();
67 if (llvmForceLogging && !logenabled) 69 if (llvmForceLogging && !logenabled)
68 { 70 {
69 Logger::enable(); 71 Logger::enable();
207 if (!global.params.output_s) { 209 if (!global.params.output_s) {
208 spath.createTemporaryFileOnDisk(); 210 spath.createTemporaryFileOnDisk();
209 } 211 }
210 Logger::println("Writing native asm to: %s\n", spath.c_str()); 212 Logger::println("Writing native asm to: %s\n", spath.c_str());
211 std::string err; 213 std::string err;
212 llvm::raw_fd_ostream out(spath.c_str(), err); 214 {
213 write_asm_to_file(*ir.module, out); 215 llvm::raw_fd_ostream out(spath.c_str(), err);
214 216 write_asm_to_file(*ir.module, out);
215 //TODO: call gcc to convert assembly to object file 217 }
218
219 // call gcc to convert assembly to object file
220 LLPath objpath = LLPath(objfile->name->toChars());
221 assemble(spath, objpath, envp);
216 222
217 if (!global.params.output_s) { 223 if (!global.params.output_s) {
218 spath.eraseFromDisk(); 224 spath.eraseFromDisk();
219 } 225 }
220 226
228 } 234 }
229 } 235 }
230 236
231 /* ================================================================== */ 237 /* ================================================================== */
232 238
239 // based on llc code, University of Illinois Open Source License
233 void write_asm_to_file(llvm::Module& m, llvm::raw_fd_ostream& out) 240 void write_asm_to_file(llvm::Module& m, llvm::raw_fd_ostream& out)
234 { 241 {
235 using namespace llvm; 242 using namespace llvm;
236 243
237 std::string Err; 244 std::string Err;
288 assert(rmod); 295 assert(rmod);
289 } 296 }
290 297
291 /* ================================================================== */ 298 /* ================================================================== */
292 299
300 // helper functions for gcc call to assemble
301 // based on llvm-ld code, University of Illinois Open Source License
302
303 /// CopyEnv - This function takes an array of environment variables and makes a
304 /// copy of it. This copy can then be manipulated any way the caller likes
305 /// without affecting the process's real environment.
306 ///
307 /// Inputs:
308 /// envp - An array of C strings containing an environment.
309 ///
310 /// Return value:
311 /// NULL - An error occurred.
312 ///
313 /// Otherwise, a pointer to a new array of C strings is returned. Every string
314 /// in the array is a duplicate of the one in the original array (i.e. we do
315 /// not copy the char *'s from one array to another).
316 ///
317 static char ** CopyEnv(char ** const envp) {
318 // Count the number of entries in the old list;
319 unsigned entries; // The number of entries in the old environment list
320 for (entries = 0; envp[entries] != NULL; entries++)
321 /*empty*/;
322
323 // Add one more entry for the NULL pointer that ends the list.
324 ++entries;
325
326 // If there are no entries at all, just return NULL.
327 if (entries == 0)
328 return NULL;
329
330 // Allocate a new environment list.
331 char **newenv = new char* [entries];
332 if ((newenv = new char* [entries]) == NULL)
333 return NULL;
334
335 // Make a copy of the list. Don't forget the NULL that ends the list.
336 entries = 0;
337 while (envp[entries] != NULL) {
338 newenv[entries] = new char[strlen (envp[entries]) + 1];
339 strcpy (newenv[entries], envp[entries]);
340 ++entries;
341 }
342 newenv[entries] = NULL;
343
344 return newenv;
345 }
346
347 // based on llvm-ld code, University of Illinois Open Source License
348
349 /// RemoveEnv - Remove the specified environment variable from the environment
350 /// array.
351 ///
352 /// Inputs:
353 /// name - The name of the variable to remove. It cannot be NULL.
354 /// envp - The array of environment variables. It cannot be NULL.
355 ///
356 /// Notes:
357 /// This is mainly done because functions to remove items from the environment
358 /// are not available across all platforms. In particular, Solaris does not
359 /// seem to have an unsetenv() function or a setenv() function (or they are
360 /// undocumented if they do exist).
361 ///
362 static void RemoveEnv(const char * name, char ** const envp) {
363 for (unsigned index=0; envp[index] != NULL; index++) {
364 // Find the first equals sign in the array and make it an EOS character.
365 char *p = strchr (envp[index], '=');
366 if (p == NULL)
367 continue;
368 else
369 *p = '\0';
370
371 // Compare the two strings. If they are equal, zap this string.
372 // Otherwise, restore it.
373 if (!strcmp(name, envp[index]))
374 *envp[index] = '\0';
375 else
376 *p = '=';
377 }
378
379 return;
380 }
381
382 // uses gcc to make an obj out of an assembly file
383 // based on llvm-ld code, University of Illinois Open Source License
384 void assemble(const llvm::sys::Path& asmpath, const llvm::sys::Path& objpath, char** envp)
385 {
386 using namespace llvm;
387
388 sys::Path gcc = llvm::sys::Program::FindProgramByName("gcc");
389
390 // Remove these environment variables from the environment of the
391 // programs that we will execute. It appears that GCC sets these
392 // environment variables so that the programs it uses can configure
393 // themselves identically.
394 //
395 // However, when we invoke GCC below, we want it to use its normal
396 // configuration. Hence, we must sanitize its environment.
397 char ** clean_env = CopyEnv(envp);
398 if (clean_env == NULL)
399 return;
400 RemoveEnv("LIBRARY_PATH", clean_env);
401 RemoveEnv("COLLECT_GCC_OPTIONS", clean_env);
402 RemoveEnv("GCC_EXEC_PREFIX", clean_env);
403 RemoveEnv("COMPILER_PATH", clean_env);
404 RemoveEnv("COLLECT_GCC", clean_env);
405
406
407 // Run GCC to assemble and link the program into native code.
408 //
409 // Note:
410 // We can't just assemble and link the file with the system assembler
411 // and linker because we don't know where to put the _start symbol.
412 // GCC mysteriously knows how to do it.
413 std::vector<std::string> args;
414 args.push_back(gcc.toString());
415 args.push_back("-fno-strict-aliasing");
416 args.push_back("-O3");
417 args.push_back("-c");
418 args.push_back("-xassembler");
419 args.push_back(asmpath.toString());
420 args.push_back("-o");
421 args.push_back(objpath.toString());
422
423 //TODO: Add other options, like -fpic
424
425 // Now that "args" owns all the std::strings for the arguments, call the c_str
426 // method to get the underlying string array. We do this game so that the
427 // std::string array is guaranteed to outlive the const char* array.
428 std::vector<const char *> Args;
429 for (unsigned i = 0, e = args.size(); i != e; ++i)
430 Args.push_back(args[i].c_str());
431 Args.push_back(0);
432
433 Logger::println("Assembling with: ");
434 std::vector<const char*>::const_iterator I = Args.begin(), E = Args.end();
435 std::ostream& logstr = Logger::cout();
436 for (; I != E; ++I)
437 if (*I)
438 logstr << "'" << *I << "'" << " ";
439 logstr << "\n" << std::flush;
440
441 // Run the compiler to assembly the program.
442 std::string ErrMsg;
443 int R = sys::Program::ExecuteAndWait(
444 gcc, &Args[0], (const char**)clean_env, 0, 0, 0, &ErrMsg);
445 delete [] clean_env;
446 }
447
448
449 /* ================================================================== */
293 // build module ctor 450 // build module ctor
294 451
295 static llvm::Function* build_module_ctor() 452 llvm::Function* build_module_ctor()
296 { 453 {
297 if (gIR->ctors.empty()) 454 if (gIR->ctors.empty())
298 return NULL; 455 return NULL;
299 456
300 size_t n = gIR->ctors.size(); 457 size_t n = gIR->ctors.size();