mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-01-21 15:23:13 +01:00
[svn r297] Fixed: rewrote linker code to use LLVM's Program facilities instead of DMD's oldschool broken "native" approach.
This commit is contained in:
293
dmd/link.c
293
dmd/link.c
@@ -37,299 +37,6 @@
|
||||
int executecmd(char *cmd, char *args, int useenv);
|
||||
int executearg0(char *cmd, char *args);
|
||||
|
||||
/*****************************
|
||||
* Run the linker. Return status of execution.
|
||||
*/
|
||||
|
||||
int runLINK()
|
||||
{
|
||||
Logger::println("*** Linking executable ***");
|
||||
|
||||
#if _WIN32
|
||||
assert(0 && "linking not done for win32");
|
||||
|
||||
char *p;
|
||||
int i;
|
||||
int status;
|
||||
OutBuffer cmdbuf;
|
||||
|
||||
global.params.libfiles->push((void *) "user32");
|
||||
global.params.libfiles->push((void *) "kernel32");
|
||||
|
||||
for (i = 0; i < global.params.objfiles->dim; i++)
|
||||
{
|
||||
if (i)
|
||||
cmdbuf.writeByte('+');
|
||||
p = (char *)global.params.objfiles->data[i];
|
||||
char *ext = FileName::ext(p);
|
||||
if (ext)
|
||||
cmdbuf.write(p, ext - p - 1);
|
||||
else
|
||||
cmdbuf.writestring(p);
|
||||
}
|
||||
cmdbuf.writeByte(',');
|
||||
if (global.params.exefile)
|
||||
cmdbuf.writestring(global.params.exefile);
|
||||
else
|
||||
{ // Generate exe file name from first obj name
|
||||
char *n = (char *)global.params.objfiles->data[0];
|
||||
char *ex;
|
||||
|
||||
n = FileName::name(n);
|
||||
FileName *fn = FileName::forceExt(n, "exe");
|
||||
global.params.exefile = fn->toChars();
|
||||
}
|
||||
|
||||
// Make sure path to exe file exists
|
||||
{ char *p = FileName::path(global.params.exefile);
|
||||
FileName::ensurePathExists(p);
|
||||
mem.free(p);
|
||||
}
|
||||
|
||||
cmdbuf.writeByte(',');
|
||||
if (global.params.run)
|
||||
cmdbuf.writestring("nul");
|
||||
// if (mapfile)
|
||||
// cmdbuf.writestring(output);
|
||||
cmdbuf.writeByte(',');
|
||||
|
||||
for (i = 0; i < global.params.libfiles->dim; i++)
|
||||
{
|
||||
if (i)
|
||||
cmdbuf.writeByte('+');
|
||||
cmdbuf.writestring((char *) global.params.libfiles->data[i]);
|
||||
}
|
||||
|
||||
if (global.params.deffile)
|
||||
{
|
||||
cmdbuf.writeByte(',');
|
||||
cmdbuf.writestring(global.params.deffile);
|
||||
}
|
||||
|
||||
/* Eliminate unnecessary trailing commas */
|
||||
while (1)
|
||||
{ i = cmdbuf.offset;
|
||||
if (!i || cmdbuf.data[i - 1] != ',')
|
||||
break;
|
||||
cmdbuf.offset--;
|
||||
}
|
||||
|
||||
if (global.params.resfile)
|
||||
{
|
||||
cmdbuf.writestring("/RC:");
|
||||
cmdbuf.writestring(global.params.resfile);
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (mapfile)
|
||||
cmdbuf.writestring("/m");
|
||||
if (debuginfo)
|
||||
cmdbuf.writestring("/li");
|
||||
if (codeview)
|
||||
{
|
||||
cmdbuf.writestring("/co");
|
||||
if (codeview3)
|
||||
cmdbuf.writestring(":3");
|
||||
}
|
||||
#else
|
||||
if (global.params.symdebug)
|
||||
cmdbuf.writestring("/co");
|
||||
#endif
|
||||
|
||||
cmdbuf.writestring("/noi");
|
||||
for (i = 0; i < global.params.linkswitches->dim; i++)
|
||||
{
|
||||
cmdbuf.writestring((char *) global.params.linkswitches->data[i]);
|
||||
}
|
||||
cmdbuf.writeByte(';');
|
||||
|
||||
p = cmdbuf.toChars();
|
||||
|
||||
FileName *lnkfilename = NULL;
|
||||
size_t plen = strlen(p);
|
||||
if (plen > 7000)
|
||||
{
|
||||
lnkfilename = FileName::forceExt(global.params.exefile, "lnk");
|
||||
File flnk(lnkfilename);
|
||||
flnk.setbuffer(p, plen);
|
||||
flnk.ref = 1;
|
||||
if (flnk.write())
|
||||
error("error writing file %s", lnkfilename);
|
||||
if (lnkfilename->len() < plen)
|
||||
sprintf(p, "@%s", lnkfilename->toChars());
|
||||
}
|
||||
|
||||
char *linkcmd = getenv("LINKCMD");
|
||||
if (!linkcmd)
|
||||
linkcmd = "link";
|
||||
status = executecmd(linkcmd, p, 1);
|
||||
if (lnkfilename)
|
||||
{
|
||||
remove(lnkfilename->toChars());
|
||||
delete lnkfilename;
|
||||
}
|
||||
return status;
|
||||
#elif linux
|
||||
pid_t childpid;
|
||||
int i;
|
||||
int status;
|
||||
|
||||
// Build argv[]
|
||||
Array argv;
|
||||
|
||||
//char *cc = getenv("CC");
|
||||
//if (!cc)
|
||||
//cc = "gcc";
|
||||
char *cc = "llvm-ld";
|
||||
argv.push((void *)cc);
|
||||
|
||||
// None of that a.out stuff. Use explicit exe file name, or
|
||||
// generate one from name of first source file.
|
||||
OutBuffer* exestr = new OutBuffer;
|
||||
if (global.params.exefile)
|
||||
{
|
||||
exestr->printf("-o=%s", global.params.exefile);
|
||||
argv.push(exestr->toChars());
|
||||
}
|
||||
else
|
||||
{ // Generate exe file name from first obj name
|
||||
char *n = (char *)global.params.objfiles->data[0];
|
||||
char *e;
|
||||
char *ex;
|
||||
|
||||
n = FileName::name(n);
|
||||
e = FileName::ext(n);
|
||||
if (e)
|
||||
{
|
||||
e--; // back up over '.'
|
||||
ex = (char *)mem.malloc(e - n + 1);
|
||||
memcpy(ex, n, e - n);
|
||||
ex[e - n] = 0;
|
||||
}
|
||||
else
|
||||
ex = (char *)"a.out"; // no extension, so give up
|
||||
exestr->printf("-o=%s", ex);
|
||||
ex = exestr->toChars();
|
||||
argv.push(ex);
|
||||
global.params.exefile = ex;
|
||||
}
|
||||
|
||||
// Make sure path to exe file exists
|
||||
{ char *p = FileName::path(global.params.exefile);
|
||||
FileName::ensurePathExists(p);
|
||||
mem.free(p);
|
||||
}
|
||||
|
||||
argv.insert(argv.dim, global.params.libfiles);
|
||||
|
||||
if (!global.params.symdebug)
|
||||
argv.push((void *)"-strip-debug");
|
||||
|
||||
//argv.push((void *)"-m32");
|
||||
|
||||
|
||||
if (!global.params.optimize)
|
||||
argv.push((void *)"-disable-opt");
|
||||
else {
|
||||
const char* s = 0;
|
||||
switch(global.params.optimizeLevel) {
|
||||
case 0:
|
||||
s = "-O0"; break;
|
||||
case 1:
|
||||
s = "-O1"; break;
|
||||
case 2:
|
||||
s = "-O2"; break;
|
||||
case 3:
|
||||
s = "-O3"; break;
|
||||
case 4:
|
||||
s = "-O4"; break;
|
||||
case 5:
|
||||
s = "-O5"; break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
argv.push((void*)s);
|
||||
}
|
||||
|
||||
if (!(global.params.useInline || global.params.llvmInline)) {
|
||||
argv.push((void *)"-disable-inlining");
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (0 && global.params.exefile)
|
||||
{
|
||||
/* This switch enables what is known as 'smart linking'
|
||||
* in the Windows world, where unreferenced sections
|
||||
* are removed from the executable. It eliminates unreferenced
|
||||
* functions, essentially making a 'library' out of a module.
|
||||
* Although it is documented to work with ld version 2.13,
|
||||
* in practice it does not, but just seems to be ignored.
|
||||
* Thomas Kuehne has verified that it works with ld 2.16.1.
|
||||
* BUG: disabled because it causes exception handling to fail
|
||||
*/
|
||||
argv.push((void *)"-Xlinker");
|
||||
argv.push((void *)"--gc-sections");
|
||||
}
|
||||
#endif
|
||||
|
||||
for (i = 0; i < global.params.linkswitches->dim; i++)
|
||||
{ char *p = (char *)global.params.linkswitches->data[i];
|
||||
//if (!p || !p[0] || !(p[0] == '-' && p[1] == 'l'))
|
||||
//{ // Don't need -Xlinker if switch starts with -l
|
||||
// argv.push((void *)"-Xlinker");
|
||||
//}
|
||||
argv.push((void *) p);
|
||||
}
|
||||
|
||||
argv.push((void*)"-native");
|
||||
|
||||
/* Standard libraries must go after user specified libraries
|
||||
* passed with -l.
|
||||
*/
|
||||
|
||||
argv.push((void*)"-ltango-base-c-llvmdc");
|
||||
argv.push((void*)"-lpthread");
|
||||
argv.push((void*)"-ldl");
|
||||
argv.push((void*)"-lm");
|
||||
|
||||
argv.append(global.params.objfiles);
|
||||
|
||||
std::string runtime_path(global.params.runtimePath);
|
||||
if (*runtime_path.rbegin() != '/')
|
||||
runtime_path.append("/");
|
||||
runtime_path.append("libtango-base-llvmdc.a");
|
||||
argv.push((void*)runtime_path.c_str());
|
||||
|
||||
if (!global.params.quiet || global.params.verbose)
|
||||
{
|
||||
// Print it
|
||||
for (i = 0; i < argv.dim; i++)
|
||||
printf("%s ", (char *)argv.data[i]);
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
argv.push(NULL);
|
||||
childpid = fork();
|
||||
if (childpid == 0)
|
||||
{
|
||||
execvp((char *)argv.data[0], (char **)argv.data);
|
||||
perror((char *)argv.data[0]); // failed to execute
|
||||
return -1;
|
||||
}
|
||||
|
||||
waitpid(childpid, &status, 0);
|
||||
|
||||
status=WEXITSTATUS(status);
|
||||
if (status)
|
||||
printf("--- errorlevel %d\n", status);
|
||||
return status;
|
||||
#else
|
||||
printf ("Linking is not yet supported for this version of LLVMDC.\n");
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**********************************
|
||||
* Delete generated EXE file.
|
||||
*/
|
||||
|
||||
@@ -1103,7 +1103,8 @@ int main(int argc, char *argv[])
|
||||
else
|
||||
{
|
||||
if (global.params.link)
|
||||
status = runLINK();
|
||||
//status = runLINK();
|
||||
linkExecutable();
|
||||
|
||||
if (global.params.run)
|
||||
{
|
||||
|
||||
@@ -304,12 +304,15 @@ void error(Loc loc, const char *format, ...);
|
||||
void verror(Loc loc, const char *format, va_list);
|
||||
void fatal();
|
||||
void err_nomem();
|
||||
int runLINK();
|
||||
//int runLINK(); // no longer used
|
||||
void deleteExeFile();
|
||||
int runProgram();
|
||||
void inifile(char *argv0, char *inifile);
|
||||
void halt();
|
||||
|
||||
// LLVMDC
|
||||
int linkExecutable();
|
||||
|
||||
/*** Where to send error messages ***/
|
||||
#if IN_GCC
|
||||
#define stdmsg stderr
|
||||
|
||||
158
gen/linker.cpp
158
gen/linker.cpp
@@ -1,8 +1,15 @@
|
||||
#include "gen/llvm.h"
|
||||
#include "llvm/Linker.h"
|
||||
#include "llvm/System/Program.h"
|
||||
|
||||
#include "root.h"
|
||||
#include "mars.h"
|
||||
#include "module.h"
|
||||
|
||||
#define NO_COUT_LOGGER
|
||||
#include "gen/logger.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef std::vector<llvm::Module*> Module_vector;
|
||||
|
||||
@@ -23,3 +30,154 @@ void linkModules(llvm::Module* dst, const Module_vector& MV)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int linkExecutable()
|
||||
{
|
||||
Logger::println("*** Linking executable ***");
|
||||
|
||||
// error string
|
||||
std::string errstr;
|
||||
|
||||
// find the llvm-ld program
|
||||
llvm::sys::Path ldpath = llvm::sys::Program::FindProgramByName("llvm-ld");
|
||||
if (ldpath.isEmpty())
|
||||
{
|
||||
error("linker program not found");
|
||||
fatal();
|
||||
}
|
||||
|
||||
// build arguments
|
||||
std::vector<const char*> args;
|
||||
|
||||
// first the program name ??
|
||||
args.push_back("llvm-ld");
|
||||
|
||||
// output filename
|
||||
std::string exestr;
|
||||
if (global.params.exefile)
|
||||
{ // explicit
|
||||
exestr = global.params.exefile;
|
||||
}
|
||||
else
|
||||
{ // inferred
|
||||
// try root module name
|
||||
if (Module::rootModule)
|
||||
exestr = Module::rootModule->toChars();
|
||||
else
|
||||
exestr = "a.out";
|
||||
}
|
||||
if (global.params.isWindows)
|
||||
exestr.append(".exe");
|
||||
|
||||
std::string outopt = "-o=" + exestr;
|
||||
args.push_back(outopt.c_str());
|
||||
|
||||
// create path to exe
|
||||
llvm::sys::Path exepath(exestr);
|
||||
exepath.set(exepath.getDirname());
|
||||
exepath.createDirectoryOnDisk(true, &errstr);
|
||||
if (!errstr.empty())
|
||||
{
|
||||
error("failed to create path to linking output\n%s", errstr.c_str());
|
||||
fatal();
|
||||
}
|
||||
|
||||
// strip debug info
|
||||
if (!global.params.symdebug)
|
||||
args.push_back("-strip-debug");
|
||||
|
||||
// optimization level
|
||||
if (!global.params.optimize)
|
||||
args.push_back("-disable-opt");
|
||||
else
|
||||
{
|
||||
const char* s = 0;
|
||||
switch(global.params.optimizeLevel)
|
||||
{
|
||||
case 0:
|
||||
s = "-O0"; break;
|
||||
case 1:
|
||||
s = "-O1"; break;
|
||||
case 2:
|
||||
s = "-O2"; break;
|
||||
case 3:
|
||||
s = "-O3"; break;
|
||||
case 4:
|
||||
s = "-O4"; break;
|
||||
case 5:
|
||||
s = "-O5"; break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
args.push_back(s);
|
||||
}
|
||||
|
||||
// inlining
|
||||
if (!(global.params.useInline || global.params.llvmInline))
|
||||
{
|
||||
args.push_back("-disable-inlining");
|
||||
}
|
||||
|
||||
// additional linker switches
|
||||
for (int i = 0; i < global.params.linkswitches->dim; i++)
|
||||
{
|
||||
char *p = (char *)global.params.linkswitches->data[i];
|
||||
args.push_back(p);
|
||||
}
|
||||
|
||||
// native please
|
||||
args.push_back("-native");
|
||||
|
||||
|
||||
// user libs
|
||||
for (int i = 0; i < global.params.libfiles->dim; i++)
|
||||
{
|
||||
char *p = (char *)global.params.libfiles->data[i];
|
||||
args.push_back(p);
|
||||
}
|
||||
|
||||
// default libs
|
||||
args.push_back("-ltango-base-c-llvmdc");
|
||||
args.push_back("-lpthread");
|
||||
args.push_back("-ldl");
|
||||
args.push_back("-lm");
|
||||
|
||||
// object files
|
||||
for (int i = 0; i < global.params.objfiles->dim; i++)
|
||||
{
|
||||
char *p = (char *)global.params.objfiles->data[i];
|
||||
args.push_back(p);
|
||||
}
|
||||
|
||||
// runtime library
|
||||
// must be linked in last to null terminate the moduleinfo appending list
|
||||
std::string runtime_path(global.params.runtimePath);
|
||||
if (*runtime_path.rbegin() != '/')
|
||||
runtime_path.append("/");
|
||||
runtime_path.append("libtango-base-llvmdc.a");
|
||||
args.push_back(runtime_path.c_str());
|
||||
|
||||
// print link command?
|
||||
if (!global.params.quiet || global.params.verbose)
|
||||
{
|
||||
// Print it
|
||||
for (int i = 0; i < args.size(); i++)
|
||||
printf("%s ", args[i]);
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
// terminate args list
|
||||
args.push_back(NULL);
|
||||
|
||||
// try to call linker!!!
|
||||
if (int status = llvm::sys::Program::ExecuteAndWait(ldpath, &args[0], NULL, NULL, 0,0, &errstr))
|
||||
{
|
||||
error("linking failed:\nstatus: %d", status);
|
||||
if (!errstr.empty())
|
||||
error("message: %s", errstr.c_str());
|
||||
fatal();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,4 +8,10 @@
|
||||
*/
|
||||
void linkModules(llvm::Module* dst, const std::vector<llvm::Module*>& MV);
|
||||
|
||||
/**
|
||||
* Link an executable.
|
||||
* @return 0 on success.
|
||||
*/
|
||||
int linkExecutable();
|
||||
|
||||
#endif // LLVMDC_GEN_LINKER_H
|
||||
|
||||
16
test/asm1.d
16
test/asm1.d
@@ -1,8 +1,20 @@
|
||||
module asm1;
|
||||
|
||||
extern(C) int printf(char*, ...);
|
||||
|
||||
void main()
|
||||
{
|
||||
version(LLVM_InlineAsm_X86_64)
|
||||
version(D_InlineAsm_X86)
|
||||
{
|
||||
int x;
|
||||
asm
|
||||
{
|
||||
mov EAX, 42;
|
||||
mov x, EAX;
|
||||
}
|
||||
printf("x = %d\n", x);
|
||||
}
|
||||
else version(D_InlineAsm_X86_64)
|
||||
{
|
||||
long x;
|
||||
asm
|
||||
@@ -14,6 +26,6 @@ void main()
|
||||
}
|
||||
else
|
||||
{
|
||||
static assert(0, "no llvm inline asm for this platform yet");
|
||||
static assert(0, "no inline asm for this platform yet");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user