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);