2004年06月25日 0:34
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 printfcsub関数は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_stopcsub_サブルーチンは、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を利用する事をお勧めする。しかしソフトウェア開発技術者なら自分で追うべきである。