<<戻る

2004年06月25日 0:34

call system('commnad')を利用したFortran77(g77)からのプログラム言語Cの呼び出し

はじめに

 Fortran77仕様には、算術ライブラリしか記載されていなかったので日付時刻の取得がFortran77では出来ないと思った。そこでプログラム言語CをFortranから呼び出して日付時刻の取得を試みたのでここに記述する。実際には、call system_clock(val)などで時間が取得できるようなのでそちらで実装した方が無難であろう。

対象者

Fortran77からの外部プログラム(c,java)などの呼び出しをしようとしている方は、別のサイトを検索した方が良いと思う。これから説明する事はアセンブラとリンカについてである。

問題点

実装する上で問題だったのは、gcc(cc1)コマンドで生成したオブジェクトとg77で生成したオブジェクトをリンケージできなかった事である。nmコマンドで確認したところgcc(cc1)コマンドとg77(=f771)の生成したアセンブラが異なるため、アセンブルしたアセンブラコードを直接編集して、リンカ(ld)の入力とした。

プリプロセスとコンパイル

#include <stdio.h>
/* file. csub.c */
void csub() {
          printf("call successfully!");
}

$ cc -c csub.c
$ ls
csub.c  csub.o

$ nm csub.o
00000000 T csub
         U printf 

csub関数はTマーク。つまり実体がこのcsub.oオブジェクトにあることを意味する。

$ cat fmain.f
*
* fmain.f
*
      PROGRAM fmain
        CALL CSUB
      END
$ g77 -c fmain.f
$ nm fmain.o
00000000 T MAIN__
         U csub_
         U s_stop
 

csub_サブルーチンは、Uマーク。つまり実体が存在しないので実体にリンクさせなければならない。ここで注目すべきはFortranプログラム上はCALL CSUBと書いたがアンダーバーがついたcsub_シンボルとなっているこれでは、リンクエラーがでる。

 

$ ld -o frun csub.o fmain.o
ld: warning: cannot find entry symbol _start; defaulting to 08048074
csub.o: In function `csub':
csub.o(.text+0xf): undefined reference to `printf'
fmain.o: In function `MAIN__':
fmain.o(.text+0x7): undefined reference to `csub_'
fmain.o(.text+0x16): undefined reference to `s_stop' 

これを解決するには、Fortran,Cどちらかのアセンブラを変更しなければならない。今回はC言語のアセンブラを
変更する.

$ cc -S csub.c
$ cat csub.s
        .file   "csub.c"
        .section        .rodata
.LC0:
        .string "call successfully!"
        .text
        .align 2
.globl csub
        .type   csub,@function
csub:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $8, %esp
        subl    $12, %esp
        pushl   $.LC0
        call    printf
        addl    $16, %esp
        leave
        ret
.Lfe1:
        .size   csub,.Lfe1-csub
        .ident  "GCC: (GNU) 3.2 20020903 (Red Hat Linux 8.0 3.2-7)" 

.file句以外のcsubとなっている部分を全てcsub_に置換する。

$ cat csub.s
        .file   "csub.c"
        .section        .rodata
.LC0:
        .string "call successfully!"
        .text
        .align 2
.globl csub_
        .type   csub_,@function
csub_:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $8, %esp
        subl    $12, %esp
        pushl   $.LC0
        call    printf
        addl    $16, %esp
        leave
        ret
.Lfe1:
        .size   csub_,.Lfe1-csub_
        .ident  "GCC: (GNU) 3.2 20020903 (Red Hat Linux 8.0 3.2-7)"

 

アセンブル

$ as -o csub.o csub.s
$ nm csub.o
00000000 T csub_
U printf

これでシンボルテーブルがcsub_に変わった。

リンク

$ ld -o frun csub.o fmain.o
ld: warning: cannot find entry symbol _start; defaulting to 08048074
csub.o: In function `csub_':
csub.o(.text+0xf): undefined reference to `printf'
fmain.o: In function `MAIN__':
fmain.o(.text+0x16): undefined reference to `s_stop' 

ldリンカコマンドでは、多くのライブラリパスを指定しなければならないのでリンクに失敗する。そのためg77コマンドでリンクする。以下は-vオプションを付加することでvarboseモードによりリンカがどのライブラリを参照しているか理解できる。

$ g77 -v csub.o fmain.o -o frun
Driving: g77 -v csub.o fmain.o -o frun -lfrtbegin -lg2c -lm -shared-libgcc
/usr/lib/gcc-lib/i386-redhat-linux/3.2/specs から spec を読み込み中
コンフィグオプション: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --enable-shared --enable-threads=posix --disable-checking --host=i386-redhat-linux --with-system-zlib --enable-__cxa_atexit
スレッドモデル: posix
gcc バージョン 3.2 20020903 (Red Hat Linux 8.0 3.2-7)
 /usr/lib/gcc-lib/i386-redhat-linux/3.2/collect2 --eh-frame-hdr -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o frun /usr/lib/gcc-lib/i386-redhat-linux/3.2/../../../crt1.o /usr/lib/gcc-lib/i386-redhat-linux/3.2/../../../crti.o /usr/lib/gcc-lib/i386-redhat-linux/3.2/crtbegin.o -L/usr/lib/gcc-lib/i386-redhat-linux/3.2 -L/usr/lib/gcc-lib/i386-redhat-linux/3.2/../../.. csub.o fmain.o -lfrtbegin -lg2c -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/lib/gcc-lib/i386-redhat-linux/3.2/crtend.o /usr/lib/gcc-lib/i386-redhat-linux/3.2/../../../crtn.o
$ ./frun
call successfully! 

最後に

はっきりいうと、ここまでくるとFortran言語入門ではない。Fortran77仕様にこだわるより単純にFortran95仕様を学び言語拡張されたコンパイラやIDEを利用する事をお勧めする。しかしソフトウェア開発技術者なら自分で追うべきである。