LoginSignup
6
3

More than 3 years have passed since last update.

「ふつうのコンパイラをつくろう」のcbcをJava8以降+64bitで動かす

Last updated at Posted at 2020-07-23

64bit環境でcbcを動作させる

「ふつうのコンパイラをつくろう」でコンパイラ入門しようとしたところ、64bit環境ではHello Worldすら動かせずに詰んだので修正箇所のメモです。
また、パッチを以下で公開しているので、ぜひご活用ください。
kamaboko123/cbc-64bit-patch

修正は主に2点。

  • Java8以降への対応
  • 64bit環境で32bit向けバイナリとしてアセンブル・リンクさせる

環境としてはUbuntu16.04 + OpenJDK9です。(それ以外の環境では動作確認をしていません)

Java8以降に対応する

Parameterクラスの衝突を修正する

net/loveruby/cflat/parser/Parser.jjを修正する。
cbcのnet.loveruby.cflat.entity.Parameter が、
Java8以降で標準ライブラリに導入されたらしい java.lang.reflect.Parameter と衝突する。
単純にParameterとなっている箇所を、完全な名前になるように修正するだけでOK。

めんどくさければこれ1行で。

sed "s/Parameter/net.loveruby.cflat.entity.Parameter/g" net/loveruby/cflat/parser/Parser.jj > net/loveruby/cflat/parser/Parser.jj.tmp; mv net/loveruby/cflat/parser/Parser.jj.tmp net/loveruby/cflat/parser/Parser.jj;

64bit環境で32bit向けにバイナリを生成するようにする

アセンブラのターゲットを32bitにするようにオプションを修正する

net/loveruby/cflat/sysdep/GNUAssembler.javaの19行目と20行目の間に、オプションを追加する。

public void assemble(String srcPath, String destPath,
                        AssemblerOptions opts) throws IPCException {
    List<String> cmd = new ArrayList<String>();
    cmd.add("as");
    cmd.add("--32");    //32bitをターゲットにするオプションを追加
    cmd.addAll(opts.args);
    cmd.add("-o");
    cmd.add(destPath);
    cmd.add(srcPath);
    CommandUtils.invoke(cmd, errorHandler, opts.verbose);
}

リンカのターゲットを32bitにするようにオプションを修正する

アセンブラだけでなく、リンカも明示的に32bitをターゲットにするように指定する必要があります。

修正箇所は net/loveruby/cflat/sysdep/GNULinker.java の29-30行目、59-60行目です。

29-30行目付近

public void generateExecutable(List<String> args,
        String destPath, LinkerOptions opts) throws IPCException {
    List<String> cmd = new ArrayList<String>();
    cmd.add(LINKER);
    cmd.add("-melf_i386");   //追加
    cmd.add("-dynamic-linker");
    cmd.add(DYNAMIC_LINKER);
    if (opts.generatingPIE) {
        cmd.add("-pie");
    }
    if (! opts.noStartFiles) {
        cmd.add(opts.generatingPIE
                    ? C_RUNTIME_START_PIE
                    : C_RUNTIME_START);
        cmd.add(C_RUNTIME_INIT);
    }
    cmd.addAll(args);
    if (! opts.noDefaultLibs) {
        cmd.add("-lc");
        cmd.add("-lcbc");
    }
    if (! opts.noStartFiles) {
        cmd.add(C_RUNTIME_FINI);
    }
    cmd.add("-o");
    cmd.add(destPath);
    CommandUtils.invoke(cmd, errorHandler, opts.verbose);
}

59-60行目付近

public void generateSharedLibrary(List<String> args,
        String destPath, LinkerOptions opts) throws IPCException {
    List<String> cmd = new ArrayList<String>();
    cmd.add(LINKER);
    cmd.add("-melf_i386");    //追加
    cmd.add("-shared");
    if (! opts.noStartFiles) {
        cmd.add(C_RUNTIME_INIT);
    }
    cmd.addAll(args);
    if (! opts.noDefaultLibs) {
        cmd.add("-lc");
        cmd.add("-lcbc");
    }
    if (! opts.noStartFiles) {
        cmd.add(C_RUNTIME_FINI);
    }
    cmd.add("-o");
    cmd.add(destPath);
    CommandUtils.invoke(cmd, errorHandler, opts.verbose);
}

また、環境によってはランタイム(スタートアップルーチン?)のパスも修正する必要があります。
Ubuntu16.04では /usr/lib にはCランタイムが存在せず、 /usr/lib32 に存在します。
シンボリックリンクを作って解決する手段もありますが、以下4行を治すだけなので、ソースコード側をいじるほうが筋は良いと思います。

net/loveruby/cflat/sysdep/GNULinker.java の12-16行目。

//修正前
//static final private String C_RUNTIME_INIT      = "/usr/lib/crti.o";
//static final private String C_RUNTIME_START     = "/usr/lib/crt1.o";
//static final private String C_RUNTIME_START_PIE = "/usr/lib/Scrt1.o";
//static final private String C_RUNTIME_FINI      = "/usr/lib/crtn.o";

//修正後
static final private String C_RUNTIME_INIT      = "/usr/lib32/crti.o";
static final private String C_RUNTIME_START     = "/usr/lib32/crt1.o";
static final private String C_RUNTIME_START_PIE = "/usr/lib32/Scrt1.o";
static final private String C_RUNTIME_FINI      = "/usr/lib32/crtn.o";

修正箇所一覧

diffです。

diff --git a/net/loveruby/cflat/parser/Parser.jj b/net/loveruby/cflat/parser/Parser.jj
index f6811b3..a73904a 100644
--- a/net/loveruby/cflat/parser/Parser.jj
+++ b/net/loveruby/cflat/parser/Parser.jj
@@ -567,7 +567,7 @@ Params params():
       LOOKAHEAD(<VOID> ")")
       t=<VOID>
         {
-            return new Params(location(t), new ArrayList<Parameter>());
+            return new Params(location(t), new ArrayList<net.loveruby.cflat.entity.Parameter>());
         }
     | params=fixedparams()
             ["," "..." { params.acceptVarargs(); }]
@@ -580,8 +580,8 @@ Params params():
 // #@@range/fixedparams{
 Params fixedparams():
 {
-    List<Parameter> params = new ArrayList<Parameter>();
-    Parameter param, param1;
+    List<net.loveruby.cflat.entity.Parameter> params = new ArrayList<net.loveruby.cflat.entity.Parameter>();
+    net.loveruby.cflat.entity.Parameter param, param1;
 }
 {
     param1=param() { params.add(param1); }
@@ -593,13 +593,13 @@ Params fixedparams():
 // #@@}

 // #@@range/param{
-Parameter param():
+net.loveruby.cflat.entity.Parameter param():
 {
     TypeNode t;
     String n;
 }
 {
-    t=type() n=name() { return new Parameter(t, n); }
+    t=type() n=name() { return new net.loveruby.cflat.entity.Parameter(t, n); }
 }
 // #@@}

diff --git a/net/loveruby/cflat/sysdep/GNUAssembler.java b/net/loveruby/cflat/sysdep/GNUAssembler.java
index 42a5a33..b95275b 100644
--- a/net/loveruby/cflat/sysdep/GNUAssembler.java
+++ b/net/loveruby/cflat/sysdep/GNUAssembler.java
@@ -17,6 +17,7 @@ class GNUAssembler implements Assembler {
                             AssemblerOptions opts) throws IPCException {
         List<String> cmd = new ArrayList<String>();
         cmd.add("as");
+        cmd.add("--32");
         cmd.addAll(opts.args);
         cmd.add("-o");
         cmd.add(destPath);
diff --git a/net/loveruby/cflat/sysdep/GNULinker.java b/net/loveruby/cflat/sysdep/GNULinker.java
index 0487d6b..a5620aa 100644
--- a/net/loveruby/cflat/sysdep/GNULinker.java
+++ b/net/loveruby/cflat/sysdep/GNULinker.java
@@ -10,10 +10,10 @@ class GNULinker implements Linker {
     // #@@range/vars{
     static final private String LINKER = "/usr/bin/ld";
     static final private String DYNAMIC_LINKER      = "/lib/ld-linux.so.2";
-    static final private String C_RUNTIME_INIT      = "/usr/lib/crti.o";
-    static final private String C_RUNTIME_START     = "/usr/lib/crt1.o";
-    static final private String C_RUNTIME_START_PIE = "/usr/lib/Scrt1.o";
-    static final private String C_RUNTIME_FINI      = "/usr/lib/crtn.o";
+    static final private String C_RUNTIME_INIT      = "/usr/lib32/crti.o";
+    static final private String C_RUNTIME_START     = "/usr/lib32/crt1.o";
+    static final private String C_RUNTIME_START_PIE = "/usr/lib32/Scrt1.o";
+    static final private String C_RUNTIME_FINI      = "/usr/lib32/crtn.o";
     // #@@}

     ErrorHandler errorHandler;
@@ -27,6 +27,7 @@ class GNULinker implements Linker {
             String destPath, LinkerOptions opts) throws IPCException {
         List<String> cmd = new ArrayList<String>();
         cmd.add(LINKER);
+        cmd.add("-melf_i386");
         cmd.add("-dynamic-linker");
         cmd.add(DYNAMIC_LINKER);
         if (opts.generatingPIE) {
@@ -57,6 +58,7 @@ class GNULinker implements Linker {
             String destPath, LinkerOptions opts) throws IPCException {
         List<String> cmd = new ArrayList<String>();
         cmd.add(LINKER);
+        cmd.add("-melf_i386");
         cmd.add("-shared");
         if (! opts.noStartFiles) {
             cmd.add(C_RUNTIME_INIT);

6
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
3