From c26eb88f2e443fdd4b6aaf7321b18e103d10bf68 Mon Sep 17 00:00:00 2001 From: Minero Aoki Date: Sun, 10 May 2009 18:18:52 +0000 Subject: [PATCH] r4834@macbookpro: aamine | 2009-05-11 03:17:05 +0900 * net/loveruby/cflat/compiler/Compiler.java: objectify assembler. * net/loveruby/cflat/compiler/Compiler.java: objectify linker. * net/loveruby/cflat/compiler/Options.java: provide #assembler, #asOptions, #linker, #ldOptions. * net/loveruby/cflat/sysdep/x86/X86Linux.java -> sysdep/X86Linux.java * net/loveruby/cflat/sysdep/Platform.java: provide #assembler, #linker. * net/loveruby/cflat/sysdep/X86Linux.java: ditto. * net/loveruby/cflat/sysdep/Assembler.java: new interface. * net/loveruby/cflat/sysdep/AssemblerOptions.java: new class. * net/loveruby/cflat/sysdep/GNUAssembler.java: new Assembler implementation. * net/loveruby/cflat/sysdep/Linker.java: new interface. * net/loveruby/cflat/sysdep/LinkerOptions.java: new clas. * net/loveruby/cflat/sysdep/GNULinker.java: new Linker implementation. * net/loveruby/cflat/utils/CommandUtils.java: new class. * net/loveruby/cflat/compiler/LdArg.java -> utils/CommandArg.java * net/loveruby/cflat/compiler/LdOption.java -> utils/CommandArgStr.java * net/loveruby/cflat/compiler/SourceFile.java: implements CommandArg. git-svn-id: file:///Users/aamine/c/gitwork/public/cbc/trunk@4207 1b9489fe-b721-0410-924e-b54b9192deb8 --- ChangeLog | 41 ++++++ net/loveruby/cflat/compiler/Compiler.java | 134 +++--------------- net/loveruby/cflat/compiler/LdArg.java | 7 - net/loveruby/cflat/compiler/LdOption.java | 18 --- net/loveruby/cflat/compiler/Options.java | 126 ++++++++-------- net/loveruby/cflat/compiler/SourceFile.java | 17 +-- net/loveruby/cflat/sysdep/Assembler.java | 7 + .../cflat/sysdep/AssemblerOptions.java | 18 +++ net/loveruby/cflat/sysdep/GNUAssembler.java | 31 ++++ net/loveruby/cflat/sysdep/GNULinker.java | 75 ++++++++++ net/loveruby/cflat/sysdep/Linker.java | 7 + net/loveruby/cflat/sysdep/LinkerOptions.java | 26 ++++ net/loveruby/cflat/sysdep/Platform.java | 2 + .../cflat/sysdep/{x86 => }/X86Linux.java | 14 +- .../cflat/sysdep/x86/CodeGenerator.java | 2 +- net/loveruby/cflat/utils/CommandArg.java | 6 + net/loveruby/cflat/utils/CommandArgStr.java | 17 +++ net/loveruby/cflat/utils/CommandUtils.java | 60 ++++++++ 18 files changed, 386 insertions(+), 222 deletions(-) delete mode 100644 net/loveruby/cflat/compiler/LdArg.java delete mode 100644 net/loveruby/cflat/compiler/LdOption.java create mode 100644 net/loveruby/cflat/sysdep/Assembler.java create mode 100644 net/loveruby/cflat/sysdep/AssemblerOptions.java create mode 100644 net/loveruby/cflat/sysdep/GNUAssembler.java create mode 100644 net/loveruby/cflat/sysdep/GNULinker.java create mode 100644 net/loveruby/cflat/sysdep/Linker.java create mode 100644 net/loveruby/cflat/sysdep/LinkerOptions.java rename net/loveruby/cflat/sysdep/{x86 => }/X86Linux.java (52%) create mode 100644 net/loveruby/cflat/utils/CommandArg.java create mode 100644 net/loveruby/cflat/utils/CommandArgStr.java create mode 100644 net/loveruby/cflat/utils/CommandUtils.java diff --git a/ChangeLog b/ChangeLog index 3f04655..b47aec2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,44 @@ +Mon May 11 03:17:32 2009 Minero Aoki + + * net/loveruby/cflat/compiler/Compiler.java: objectify assembler. + + * net/loveruby/cflat/compiler/Compiler.java: objectify linker. + + * net/loveruby/cflat/compiler/Options.java: provide #assembler, + #asOptions, #linker, #ldOptions. + + * net/loveruby/cflat/sysdep/x86/X86Linux.java -> + sysdep/X86Linux.java + + * net/loveruby/cflat/sysdep/Platform.java: provide #assembler, + #linker. + + * net/loveruby/cflat/sysdep/X86Linux.java: ditto. + + * net/loveruby/cflat/sysdep/Assembler.java: new interface. + + * net/loveruby/cflat/sysdep/AssemblerOptions.java: new class. + + * net/loveruby/cflat/sysdep/GNUAssembler.java: new Assembler + implementation. + + * net/loveruby/cflat/sysdep/Linker.java: new interface. + + * net/loveruby/cflat/sysdep/LinkerOptions.java: new clas. + + * net/loveruby/cflat/sysdep/GNULinker.java: new Linker + implementation. + + * net/loveruby/cflat/utils/CommandUtils.java: new class. + + * net/loveruby/cflat/compiler/LdArg.java -> utils/CommandArg.java + + * net/loveruby/cflat/compiler/LdOption.java -> + utils/CommandArgStr.java + + * net/loveruby/cflat/compiler/SourceFile.java: implements + CommandArg. + Mon May 11 01:49:29 2009 Minero Aoki * net/loveruby/cflat/parser/Parser.jj: use JDK_VERSION="1.5" to diff --git a/net/loveruby/cflat/compiler/Compiler.java b/net/loveruby/cflat/compiler/Compiler.java index 94f4a5c..b8ea8bf 100644 --- a/net/loveruby/cflat/compiler/Compiler.java +++ b/net/loveruby/cflat/compiler/Compiler.java @@ -19,7 +19,7 @@ public class Compiler { new Compiler(ProgramName).commandMain(args); } - protected ErrorHandler errorHandler; + private ErrorHandler errorHandler; public Compiler(String programName) { this.errorHandler = new ErrorHandler(programName); @@ -67,7 +67,7 @@ public class Compiler { System.exit(1); } - protected boolean isValidSyntax(SourceFile src, Options opts) { + private boolean isValidSyntax(SourceFile src, Options opts) { try { parseFile(src, opts); return true; @@ -82,7 +82,7 @@ public class Compiler { } // #@@range/buildTarget{ - protected void buildTarget(List srcs, Options opts) + public void buildTarget(List srcs, Options opts) throws CompileException { for (SourceFile src : srcs) { compileFile(src, opts); @@ -97,7 +97,7 @@ public class Compiler { } // #@@} - protected void compileFile(SourceFile src, Options opts) + public void compileFile(SourceFile src, Options opts) throws CompileException { if (src.isCflatSource()) { AST ast = parseFile(src, opts); @@ -163,7 +163,7 @@ public class Compiler { return expr; } - protected AST parseFile(SourceFile src, Options opts) + public AST parseFile(SourceFile src, Options opts) throws SyntaxException, FileException { return Parser.parseFile(new File(src.currentName()), opts.loader(), @@ -171,7 +171,7 @@ public class Compiler { opts.doesDebugParser()); } - protected void semanticAnalysis(AST ast, Options opts) + public void semanticAnalysis(AST ast, Options opts) throws SemanticException { new LocalResolver(errorHandler).resolve(ast); new TypeResolver(errorHandler).resolve(ast); @@ -184,129 +184,29 @@ public class Compiler { new TypeChecker(errorHandler).check(ast); } - protected String generateAssembly(IR ir, Options opts) { + public String generateAssembly(IR ir, Options opts) { CodeGenerator gen = opts.codeGenerator(errorHandler); return gen.generate(ir); } - protected void assemble(String srcPath, + private void assemble(String srcPath, String destPath, Options opts) throws IPCException { - List cmd = new ArrayList(); - cmd.add("as"); - cmd.addAll(opts.asOptions()); - cmd.add("-o"); - cmd.add(destPath); - cmd.add(srcPath); - invoke(cmd, opts.isVerboseMode()); + opts.assembler(errorHandler) + .assemble(srcPath, destPath, opts.asOptions()); } - static final protected String DYNAMIC_LINKER = "/lib/ld-linux.so.2"; - static final protected String C_RUNTIME_INIT = "/usr/lib/crti.o"; - static final protected String C_RUNTIME_START = "/usr/lib/crt1.o"; - static final protected String C_RUNTIME_START_PIE = "/usr/lib/Scrt1.o"; - static final protected String C_RUNTIME_FINI = "/usr/lib/crtn.o"; - - protected void generateExecutable(Options opts) throws IPCException { - List cmd = new ArrayList(); - cmd.add("ld"); - cmd.add("-dynamic-linker"); - cmd.add(DYNAMIC_LINKER); - if (opts.isGeneratingPIE()) { - cmd.add("-pie"); - } - if (! opts.noStartFiles()) { - cmd.add(opts.isGeneratingPIE() - ? C_RUNTIME_START_PIE - : C_RUNTIME_START); - cmd.add(C_RUNTIME_INIT); - } - cmd.addAll(opts.ldArgs()); - if (! opts.noDefaultLibs()) { - cmd.add("-lc"); - cmd.add("-lcbc"); - } - if (! opts.noStartFiles()) { - cmd.add(C_RUNTIME_FINI); - } - cmd.add("-o"); - cmd.add(opts.exeFileName()); - invoke(cmd, opts.isVerboseMode()); + private void generateExecutable(Options opts) throws IPCException { + opts.linker(errorHandler) + .generateExecutable(opts.exeFileName(), opts.ldOptions()); } - protected void generateSharedLibrary(Options opts) throws IPCException { - List cmd = new ArrayList(); - cmd.add("ld"); - cmd.add("-shared"); - if (! opts.noStartFiles()) { - cmd.add(C_RUNTIME_INIT); - } - cmd.addAll(opts.ldArgs()); - if (! opts.noDefaultLibs()) { - cmd.add("-lc"); - cmd.add("-lcbc"); - } - if (! opts.noStartFiles()) { - cmd.add(C_RUNTIME_FINI); - } - cmd.add("-o"); - cmd.add(opts.soFileName()); - invoke(cmd, opts.isVerboseMode()); + private void generateSharedLibrary(Options opts) throws IPCException { + opts.linker(errorHandler) + .generateSharedLibrary(opts.soFileName(), opts.ldOptions()); } - protected void invoke(List cmdArgs, boolean debug) throws IPCException { - if (debug) { - dumpCommand(cmdArgs); - } - try { - String[] cmd = getStrings(cmdArgs); - Process proc = Runtime.getRuntime().exec(cmd); - proc.waitFor(); - passThrough(proc.getInputStream()); - passThrough(proc.getErrorStream()); - if (proc.exitValue() != 0) { - errorHandler.error(cmd[0] + " failed." - + " (status " + proc.exitValue() + ")"); - throw new IPCException("compile error"); - } - } - catch (InterruptedException ex) { - errorHandler.error("gcc interrupted: " + ex.getMessage()); - throw new IPCException("compile error"); - } - catch (IOException ex) { - errorHandler.error(ex.getMessage()); - throw new IPCException("compile error"); - } - } - - protected String[] getStrings(List list) { - String[] a = new String[list.size()]; - int idx = 0; - for (Object o : list) { - a[idx++] = o.toString(); - } - return a; - } - - protected void dumpCommand(List args) { - String sep = ""; - for (Object arg : args) { - System.out.print(sep); sep = " "; - System.out.print(arg.toString()); - } - System.out.println(""); - } - - protected void passThrough(InputStream s) throws IOException { - BufferedReader r = new BufferedReader(new InputStreamReader(s)); - String line; - while ((line = r.readLine()) != null) { - System.err.println(line); - } - } - - protected void writeFile(String path, String str) + private void writeFile(String path, String str) throws FileException { try { BufferedWriter f = new BufferedWriter( diff --git a/net/loveruby/cflat/compiler/LdArg.java b/net/loveruby/cflat/compiler/LdArg.java deleted file mode 100644 index 42a2a87..0000000 --- a/net/loveruby/cflat/compiler/LdArg.java +++ /dev/null @@ -1,7 +0,0 @@ -package net.loveruby.cflat.compiler; - -// package private -interface LdArg { - abstract public String toString(); - abstract public boolean isSourceFile(); -} diff --git a/net/loveruby/cflat/compiler/LdOption.java b/net/loveruby/cflat/compiler/LdOption.java deleted file mode 100644 index 84e00be..0000000 --- a/net/loveruby/cflat/compiler/LdOption.java +++ /dev/null @@ -1,18 +0,0 @@ -package net.loveruby.cflat.compiler; - -// package private -class LdOption implements LdArg { - protected String option; - - public LdOption(String option) { - this.option = option; - } - - public boolean isSourceFile() { - return false; - } - - public String toString() { - return this.option; - } -} diff --git a/net/loveruby/cflat/compiler/Options.java b/net/loveruby/cflat/compiler/Options.java index 92549d6..d015d2e 100644 --- a/net/loveruby/cflat/compiler/Options.java +++ b/net/loveruby/cflat/compiler/Options.java @@ -3,13 +3,13 @@ import net.loveruby.cflat.parser.LibraryLoader; import net.loveruby.cflat.type.TypeTable; import net.loveruby.cflat.asm.*; import net.loveruby.cflat.sysdep.*; -import net.loveruby.cflat.sysdep.x86.X86Linux; +import net.loveruby.cflat.sysdep.X86Linux; +import net.loveruby.cflat.utils.CommandArg; import net.loveruby.cflat.utils.ErrorHandler; import net.loveruby.cflat.exception.*; import java.util.*; import java.io.*; -// package scope class Options { CompilerMode mode; LibraryLoader loader = new LibraryLoader(); @@ -18,12 +18,8 @@ class Options { boolean verbose = false; boolean debugParser = false; CodeGeneratorOptions genOptions = new CodeGeneratorOptions(); - List asOptions = new ArrayList(); - boolean generatingSharedLibrary = false; - boolean generatingPIE = false; - List ldArgs = new ArrayList(); - boolean noStartFiles = false; - boolean noDefaultLibs = false; + AssemblerOptions asOptions = new AssemblerOptions(); + LinkerOptions ldOptions = new LinkerOptions(); CompilerMode mode() { return mode; @@ -64,7 +60,7 @@ class Options { private List sourceFiles() { List result = new ArrayList(); - for (LdArg arg : ldArgs) { + for (CommandArg arg : ldOptions.args()) { if (arg.isSourceFile()) { result.add((SourceFile)arg); } @@ -72,22 +68,6 @@ class Options { return result; } - Platform platform() { - return platform; - } - - TypeTable typeTable() { - return platform.typeTable(); - } - - CodeGenerator codeGenerator(ErrorHandler errorHandler) { - return platform.codeGenerator(genOptions, errorHandler); - } - - LibraryLoader loader() { - return this.loader; - } - String outputFileName() { return this.outputFileName; } @@ -100,28 +80,36 @@ class Options { return this.debugParser; } - List asOptions() { - return this.asOptions; + LibraryLoader loader() { + return this.loader; + } + + TypeTable typeTable() { + return platform.typeTable(); + } + + CodeGenerator codeGenerator(ErrorHandler h) { + return platform.codeGenerator(genOptions, h); + } + + Assembler assembler(ErrorHandler h) { + return platform.assembler(h); + } + + AssemblerOptions asOptions() { + return asOptions; + } + + Linker linker(ErrorHandler h) { + return platform.linker(h); + } + + LinkerOptions ldOptions() { + return ldOptions; } boolean isGeneratingSharedLibrary() { - return this.generatingSharedLibrary; - } - - boolean isGeneratingPIE() { - return this.generatingPIE; - } - - List ldArgs() { - return this.ldArgs; - } - - boolean noStartFiles() { - return this.noStartFiles; - } - - boolean noDefaultLibs() { - return this.noDefaultLibs; + return ldOptions.generatingSharedLibrary; } /** Returns List. */ @@ -170,54 +158,58 @@ class Options { genOptions.generateVerboseAsm(); } else if (arg.startsWith("-Wa,")) { - asOptions.addAll(parseCommaSeparatedOptions(arg)); + for (String a : parseCommaSeparatedOptions(arg)) { + asOptions.addArg(a); + } } else if (arg.equals("-Xassembler")) { - asOptions.add(nextArg(arg, args)); + asOptions.addArg(nextArg(arg, args)); } else if (arg.equals("-static")) { - ldArgs.add(new LdOption(arg)); + ldOptions.addArg(arg); } else if (arg.equals("-shared")) { - generatingSharedLibrary = true; + ldOptions.generatingSharedLibrary = true; } else if (arg.equals("-pie")) { - generatingPIE = true; + ldOptions.generatingPIE = true; } else if (arg.equals("--readonly-plt")) { - ldArgs.add(new LdOption("-z")); - ldArgs.add(new LdOption("combreloc")); - ldArgs.add(new LdOption("-z")); - ldArgs.add(new LdOption("now")); - ldArgs.add(new LdOption("-z")); - ldArgs.add(new LdOption("relro")); + ldOptions.addArg("-z"); + ldOptions.addArg("combreloc"); + ldOptions.addArg("-z"); + ldOptions.addArg("now"); + ldOptions.addArg("-z"); + ldOptions.addArg("relro"); } else if (arg.startsWith("-L")) { - ldArgs.add(new LdOption("-L" + getOptArg(arg, args))); + ldOptions.addArg("-L" + getOptArg(arg, args)); } else if (arg.startsWith("-l")) { - ldArgs.add(new LdOption("-l" + getOptArg(arg, args))); + ldOptions.addArg("-l" + getOptArg(arg, args)); } else if (arg.equals("-nostartfiles")) { - noStartFiles = true; + ldOptions.noStartFiles = true; } else if (arg.equals("-nodefaultlibs")) { - noDefaultLibs = true; + ldOptions.noDefaultLibs = true; } else if (arg.equals("-nostdlib")) { - noStartFiles = true; - noDefaultLibs = true; + ldOptions.noStartFiles = true; + ldOptions.noDefaultLibs = true; } else if (arg.startsWith("-Wl,")) { for (String opt : parseCommaSeparatedOptions(arg)) { - ldArgs.add(new LdOption(opt)); + ldOptions.addArg(opt); } } else if (arg.equals("-Xlinker")) { - ldArgs.add(new LdOption(nextArg(arg, args))); + ldOptions.addArg(nextArg(arg, args)); } else if (arg.equals("-v")) { verbose = true; + asOptions.verbose = true; + ldOptions.verbose = true; } else if (arg.equals("--version")) { System.out.printf("%s version %s", @@ -234,12 +226,12 @@ class Options { } else { // source file - addSourceFile(srcs, ldArgs, arg); + addSourceFile(srcs, arg); } } // args has more arguments when "--" is appeared. while (args.hasNext()) { - addSourceFile(srcs, ldArgs, args.next()); + addSourceFile(srcs, args.next()); } if (srcs.isEmpty()) parseError("no input file"); if (mode == null) { @@ -255,11 +247,11 @@ class Options { throw new OptionParseError(msg); } - private void addSourceFile(List srcs, List ldArgs, String sourceName) { + private void addSourceFile(List srcs, String sourceName) { SourceFile src = new SourceFile(sourceName); srcs.add(src); // Original argument order does matter when linking. - ldArgs.add(src); + ldOptions.addArg(src); } private String getOptArg(String opt, ListIterator args) { diff --git a/net/loveruby/cflat/compiler/SourceFile.java b/net/loveruby/cflat/compiler/SourceFile.java index 814a353..1e58f62 100644 --- a/net/loveruby/cflat/compiler/SourceFile.java +++ b/net/loveruby/cflat/compiler/SourceFile.java @@ -1,10 +1,11 @@ package net.loveruby.cflat.compiler; +import net.loveruby.cflat.utils.CommandArg; import java.io.File; // package private -class SourceFile implements LdArg { - protected String originalName; - protected String currentName; +class SourceFile implements CommandArg { + private String originalName; + private String currentName; public SourceFile(String name) { this.originalName = name; @@ -63,19 +64,19 @@ class SourceFile implements LdArg { return or(opts.outputFileName, replaceExt(newExt)); } - protected String or(String x, String y) { + private String or(String x, String y) { return x != null ? x : y; } - protected String replaceExt(String ext) { + private String replaceExt(String ext) { return baseName(originalName, true) + ext; } - protected String baseName(String path) { + private String baseName(String path) { return new File(path).getName(); } - protected String baseName(String path, boolean stripExt) { + private String baseName(String path, boolean stripExt) { if (stripExt) { return new File(path).getName().replaceFirst("\\.[^.]*$", ""); } @@ -84,7 +85,7 @@ class SourceFile implements LdArg { } } - protected String extName(String path) { + private String extName(String path) { int idx = path.lastIndexOf("."); if (idx < 0) return ""; return path.substring(idx); diff --git a/net/loveruby/cflat/sysdep/Assembler.java b/net/loveruby/cflat/sysdep/Assembler.java new file mode 100644 index 0000000..cb3aed6 --- /dev/null +++ b/net/loveruby/cflat/sysdep/Assembler.java @@ -0,0 +1,7 @@ +package net.loveruby.cflat.sysdep; +import net.loveruby.cflat.exception.IPCException; + +public interface Assembler { + void assemble(String srcPath, String destPath, + AssemblerOptions opts) throws IPCException; +} diff --git a/net/loveruby/cflat/sysdep/AssemblerOptions.java b/net/loveruby/cflat/sysdep/AssemblerOptions.java new file mode 100644 index 0000000..c700c2f --- /dev/null +++ b/net/loveruby/cflat/sysdep/AssemblerOptions.java @@ -0,0 +1,18 @@ +package net.loveruby.cflat.sysdep; +import net.loveruby.cflat.utils.CommandArg; +import net.loveruby.cflat.utils.CommandArgStr; +import java.util.List; +import java.util.ArrayList; + +public class AssemblerOptions { + public boolean verbose = false; + List args = new ArrayList(); + + public void addArg(String a) { + args.add(new CommandArgStr(a)); + } + + public void addArg(CommandArg a) { + args.add(a); + } +} diff --git a/net/loveruby/cflat/sysdep/GNUAssembler.java b/net/loveruby/cflat/sysdep/GNUAssembler.java new file mode 100644 index 0000000..1b33684 --- /dev/null +++ b/net/loveruby/cflat/sysdep/GNUAssembler.java @@ -0,0 +1,31 @@ +package net.loveruby.cflat.sysdep; +import net.loveruby.cflat.utils.CommandUtils; +import net.loveruby.cflat.utils.CommandArg; +import net.loveruby.cflat.utils.CommandArgStr; +import net.loveruby.cflat.utils.ErrorHandler; +import net.loveruby.cflat.exception.IPCException; +import java.util.List; +import java.util.ArrayList; + +class GNUAssembler implements Assembler { + ErrorHandler errorHandler; + + GNUAssembler(ErrorHandler h) { + this.errorHandler = h; + } + + public void assemble(String srcPath, String destPath, + AssemblerOptions opts) throws IPCException { + List cmd = new ArrayList(); + cmd.add(arg("as")); + cmd.addAll(opts.args); + cmd.add(arg("-o")); + cmd.add(arg(destPath)); + cmd.add(arg(srcPath)); + CommandUtils.invoke(cmd, errorHandler, opts.verbose); + } + + private CommandArg arg(String a) { + return new CommandArgStr(a); + } +} diff --git a/net/loveruby/cflat/sysdep/GNULinker.java b/net/loveruby/cflat/sysdep/GNULinker.java new file mode 100644 index 0000000..14f2c91 --- /dev/null +++ b/net/loveruby/cflat/sysdep/GNULinker.java @@ -0,0 +1,75 @@ +package net.loveruby.cflat.sysdep; +import net.loveruby.cflat.utils.CommandUtils; +import net.loveruby.cflat.utils.CommandArg; +import net.loveruby.cflat.utils.CommandArgStr; +import net.loveruby.cflat.utils.ErrorHandler; +import net.loveruby.cflat.exception.IPCException; +import java.util.List; +import java.util.ArrayList; + +class GNULinker implements Linker { + static final protected String DYNAMIC_LINKER = "/lib/ld-linux.so.2"; + static final protected String C_RUNTIME_INIT = "/usr/lib/crti.o"; + static final protected String C_RUNTIME_START = "/usr/lib/crt1.o"; + static final protected String C_RUNTIME_START_PIE = "/usr/lib/Scrt1.o"; + static final protected String C_RUNTIME_FINI = "/usr/lib/crtn.o"; + + ErrorHandler errorHandler; + + GNULinker(ErrorHandler errorHandler) { + this.errorHandler = errorHandler; + } + + public void generateExecutable( + String destPath, LinkerOptions opts) throws IPCException { + List cmd = new ArrayList(); + cmd.add(arg("ld")); + cmd.add(arg("-dynamic-linker")); + cmd.add(arg(DYNAMIC_LINKER)); + if (opts.generatingPIE) { + cmd.add(arg("-pie")); + } + if (! opts.noStartFiles) { + cmd.add(arg(opts.generatingPIE + ? C_RUNTIME_START_PIE + : C_RUNTIME_START)); + cmd.add(arg(C_RUNTIME_INIT)); + } + cmd.addAll(opts.args); + if (! opts.noDefaultLibs) { + cmd.add(arg("-lc")); + cmd.add(arg("-lcbc")); + } + if (! opts.noStartFiles) { + cmd.add(arg(C_RUNTIME_FINI)); + } + cmd.add(arg("-o")); + cmd.add(arg(destPath)); + CommandUtils.invoke(cmd, errorHandler, opts.verbose); + } + + public void generateSharedLibrary( + String destPath, LinkerOptions opts) throws IPCException { + List cmd = new ArrayList(); + cmd.add(arg("ld")); + cmd.add(arg("-shared")); + if (! opts.noStartFiles) { + cmd.add(arg(C_RUNTIME_INIT)); + } + cmd.addAll(opts.args); + if (! opts.noDefaultLibs) { + cmd.add(arg("-lc")); + cmd.add(arg("-lcbc")); + } + if (! opts.noStartFiles) { + cmd.add(arg(C_RUNTIME_FINI)); + } + cmd.add(arg("-o")); + cmd.add(arg(destPath)); + CommandUtils.invoke(cmd, errorHandler, opts.verbose); + } + + private CommandArg arg(String a) { + return new CommandArgStr(a); + } +} diff --git a/net/loveruby/cflat/sysdep/Linker.java b/net/loveruby/cflat/sysdep/Linker.java new file mode 100644 index 0000000..f0fbf8f --- /dev/null +++ b/net/loveruby/cflat/sysdep/Linker.java @@ -0,0 +1,7 @@ +package net.loveruby.cflat.sysdep; +import net.loveruby.cflat.exception.IPCException; + +public interface Linker { + void generateExecutable(String destPath, LinkerOptions opts) throws IPCException; + void generateSharedLibrary(String destPath, LinkerOptions opts) throws IPCException; +} diff --git a/net/loveruby/cflat/sysdep/LinkerOptions.java b/net/loveruby/cflat/sysdep/LinkerOptions.java new file mode 100644 index 0000000..a498012 --- /dev/null +++ b/net/loveruby/cflat/sysdep/LinkerOptions.java @@ -0,0 +1,26 @@ +package net.loveruby.cflat.sysdep; +import net.loveruby.cflat.utils.CommandArg; +import net.loveruby.cflat.utils.CommandArgStr; +import java.util.List; +import java.util.ArrayList; + +public class LinkerOptions { + public boolean generatingSharedLibrary = false; + public boolean generatingPIE = false; + public boolean noStartFiles = false; + public boolean noDefaultLibs = false; + public boolean verbose = false; + List args = new ArrayList(); + + public void addArg(String a) { + args.add(new CommandArgStr(a)); + } + + public void addArg(CommandArg a) { + args.add(a); + } + + public List args() { + return this.args; + } +} diff --git a/net/loveruby/cflat/sysdep/Platform.java b/net/loveruby/cflat/sysdep/Platform.java index 0ec1404..b5e61fc 100644 --- a/net/loveruby/cflat/sysdep/Platform.java +++ b/net/loveruby/cflat/sysdep/Platform.java @@ -5,4 +5,6 @@ import net.loveruby.cflat.utils.ErrorHandler; public interface Platform { TypeTable typeTable(); CodeGenerator codeGenerator(CodeGeneratorOptions opts, ErrorHandler h); + Assembler assembler(ErrorHandler h); + Linker linker(ErrorHandler h); } diff --git a/net/loveruby/cflat/sysdep/x86/X86Linux.java b/net/loveruby/cflat/sysdep/X86Linux.java similarity index 52% rename from net/loveruby/cflat/sysdep/x86/X86Linux.java rename to net/loveruby/cflat/sysdep/X86Linux.java index 3b64d12..3a6d2fb 100644 --- a/net/loveruby/cflat/sysdep/x86/X86Linux.java +++ b/net/loveruby/cflat/sysdep/X86Linux.java @@ -1,6 +1,4 @@ -package net.loveruby.cflat.sysdep.x86; -import net.loveruby.cflat.sysdep.Platform; -import net.loveruby.cflat.sysdep.CodeGeneratorOptions; +package net.loveruby.cflat.sysdep; import net.loveruby.cflat.utils.ErrorHandler; import net.loveruby.cflat.type.TypeTable; @@ -11,6 +9,14 @@ public class X86Linux implements Platform { public CodeGenerator codeGenerator( CodeGeneratorOptions opts, ErrorHandler h) { - return new CodeGenerator(opts, h); + return new net.loveruby.cflat.sysdep.x86.CodeGenerator(opts, h); + } + + public Assembler assembler(ErrorHandler h) { + return new GNUAssembler(h); + } + + public Linker linker(ErrorHandler h) { + return new GNULinker(h); } } diff --git a/net/loveruby/cflat/sysdep/x86/CodeGenerator.java b/net/loveruby/cflat/sysdep/x86/CodeGenerator.java index fb901fe..f749ed0 100644 --- a/net/loveruby/cflat/sysdep/x86/CodeGenerator.java +++ b/net/loveruby/cflat/sysdep/x86/CodeGenerator.java @@ -8,7 +8,7 @@ import net.loveruby.cflat.utils.AsmUtils; import net.loveruby.cflat.utils.ErrorHandler; import java.util.*; -class CodeGenerator +public class CodeGenerator implements net.loveruby.cflat.sysdep.CodeGenerator, IRVisitor, ELFConstants { diff --git a/net/loveruby/cflat/utils/CommandArg.java b/net/loveruby/cflat/utils/CommandArg.java new file mode 100644 index 0000000..f8526d1 --- /dev/null +++ b/net/loveruby/cflat/utils/CommandArg.java @@ -0,0 +1,6 @@ +package net.loveruby.cflat.utils; + +public interface CommandArg { + public String toString(); + public boolean isSourceFile(); +} diff --git a/net/loveruby/cflat/utils/CommandArgStr.java b/net/loveruby/cflat/utils/CommandArgStr.java new file mode 100644 index 0000000..75a86dd --- /dev/null +++ b/net/loveruby/cflat/utils/CommandArgStr.java @@ -0,0 +1,17 @@ +package net.loveruby.cflat.utils; + +public class CommandArgStr implements CommandArg { + private String arg; + + public CommandArgStr(String arg) { + this.arg = arg; + } + + public boolean isSourceFile() { + return false; + } + + public String toString() { + return arg; + } +} diff --git a/net/loveruby/cflat/utils/CommandUtils.java b/net/loveruby/cflat/utils/CommandUtils.java new file mode 100644 index 0000000..b7c55b8 --- /dev/null +++ b/net/loveruby/cflat/utils/CommandUtils.java @@ -0,0 +1,60 @@ +package net.loveruby.cflat.utils; +import net.loveruby.cflat.exception.IPCException; +import java.util.List; +import java.util.ArrayList; +import java.io.*; + +abstract public class CommandUtils { + static public void invoke(List cmdArgs, + ErrorHandler errorHandler, boolean debug) throws IPCException { + if (debug) { + dumpCommand(cmdArgs); + } + try { + String[] cmd = getStrings(cmdArgs); + Process proc = Runtime.getRuntime().exec(cmd); + proc.waitFor(); + passThrough(proc.getInputStream()); + passThrough(proc.getErrorStream()); + if (proc.exitValue() != 0) { + errorHandler.error(cmd[0] + " failed." + + " (status " + proc.exitValue() + ")"); + throw new IPCException("compile error"); + } + } + catch (InterruptedException ex) { + errorHandler.error("gcc interrupted: " + ex.getMessage()); + throw new IPCException("compile error"); + } + catch (IOException ex) { + errorHandler.error(ex.getMessage()); + throw new IPCException("compile error"); + } + } + + static private String[] getStrings(List list) { + String[] result = new String[list.size()]; + int idx = 0; + for (CommandArg arg : list) { + result[idx++] = arg.toString(); + } + return result; + } + + static private void dumpCommand(List args) { + String sep = ""; + for (CommandArg arg : args) { + System.out.print(sep); sep = " "; + System.out.print(arg.toString()); + } + System.out.println(""); + } + + static private void passThrough(InputStream s) throws IOException { + BufferedReader r = new BufferedReader(new InputStreamReader(s)); + String line; + while ((line = r.readLine()) != null) { + System.err.println(line); + } + } +}