LoginSignup
5
3

More than 5 years have passed since last update.

Ancient UNIXのcrt0.sを読む

Last updated at Posted at 2015-11-18

UNIX V6とV7のcrt0.sを読んで、スタックで渡されるコマンドライン引数の形式を調べました。V7をVAXに移植したUNIX/32Vや、Interdata 7/32に移植したV6とも比較します。

※ カーネルのexecシステムコールを読む方が確実ですが、今回はアセンブリ言語を読むため敢えてcrt0.sから読み取りました。

作業時のメモをツイートしました。

argv

C言語で文字列配列の構造を見ます。

str.c
char *argv[] { "abc", "def" };

※ pre K/Rではグローバル変数への代入に = を使用しません。

次のような構造が出力されます。

アドレス 内容 備考
0000 0004 文字列のアドレス: argv[0]
0002 0008 文字列のアドレス: argv[1]
0004 abc\0 文字列
0008 def\0 文字列

文字列のアドレスが並び、その後に文字列の実データが格納されます。main()に渡されるargvはカーネルが同様の構造をスタックに生成して渡します。

UNIX V6

main()が呼ばれるまでは短いです。コメントに疑似コードで動作を示します。

    mov sp,r0       / r0 = sp
    mov (r0),-(sp)  / sp -= 2; argc = *r0
    tst (r0)+       / r0 += 2
    mov r0,2(sp)    / argv = r0
    jsr pc,_main    / main(argc, argv)

引数はスタック渡しです。起動直後とmain()が呼ばれる直前のスタックの変化を示します。

アドレス 起動直後 アドレス main直前 備考
(sp) argc 移動
(sp) argc 2(sp) argv 追記
2(sp) argv[0] 4(sp) argv[0] そのまま

argcを1つ前にずらしてargvを挿入しています。

UNIX V7

envpが加わったためV6より複雑になっています。コメントに疑似コードで動作を示します。

    mov 2(sp),r0     / r0 = argv[0]
    clr -2(r0)       / *(r0-2) = 0
    mov sp,r0        / r0 = sp
    sub $4,sp        / sp -= 4
    mov 4(sp),(sp)   / argc = *(sp+4)
    tst (r0)+        / r0 += 2
    mov r0,2(sp)     / argv = r0
1:                   / do {
    tst (r0)+        /     tmp = *r0; r0 += 2
    bne 1b           / } while (tmp)
    cmp r0,*2(sp)    / if (r0 >= argv[0])
    blo 1f           / {
    tst -(r0)        /     r0 -= 2
1:                   / }
    mov r0,4(sp)     / envp = r0
    mov r0,_environ  / environ = r0
    jsr pc,_main     / main(argc, argv, envp)

引数はスタック渡しです。起動直後とmain()が呼ばれる直前のスタックの変化を示します。

アドレス 起動直後 アドレス main直前 備考
(sp) argc 移動
2(sp) argv 追記
(sp) argc 4(sp) envp 上書き
2(sp) argv[0] 6(sp) argv[0] そのまま

argcを2つ前にずらしてargvenvpを挿入しています。

argv[]envp[]NULLで区切られています。

  • argv[0], ... , NULL, envp[0], ..., NULL

最初のNULLをループ(do {} whileで示した部分)で探しています。

ifで示した部分は、もしenvpが存在せずNULLも1個しかなかった場合、r0 -= 2で最初のNULLを指すように補正しています。

NULLがなければ誤動作するため、最後のポインタを潰してでもNULLを作っているのがclr -2(r0)の部分です。

UNIX/32V

V7をなるべくそのまま32bit化したような印象です。最初からコメントが入っています。

    subl2   $8,sp
    movl    8(sp),(sp)   # argc
    movab   12(sp),r0
    movl    r0,4(sp)     # argv
L1:
    tstl    (r0)+        # null args term ?
    bneq    L1
    cmpl    r0,*4(sp)    # end of 'env' or 'argv' ?
    blss    L2
    tstl    -(r0)        # envp's are in list
L2:
    movl    r0,8(sp)     # env
    movl    r0,_environ  # indir is 0 if no env ; not 0 if env
    calls   $3,_main

引数はスタック渡しです。起動直後とmain()が呼ばれる直前のスタックの変化を示します。

アドレス 起動直後 アドレス main直前 備考
(sp) argc 移動
4(sp) argv 追記
(sp) argc 8(sp) envp 上書き
4(sp) argv[0] 12(sp) argv[0] そのまま

argcを2つ前にずらしてargvenvpを挿入しています。

UNIX V6 for Interdata 7/32

V6の移植版です。Interdata 7/32は32bitのビッグエンディアンのアーキテクチャです。

SIMHで動かせます。

crt0.sを含むlibcのソースはアーカイブされたままです。

このsrc.aはGNU Binutilsと互換性がありません。

$ file src.a
src.a: old 32-bit-int big-endian archive
$ ar x src.a
ar: src.a: ファイル形式が認識できません

仕方ないので当時のarをPOSIXにやっつけで移植しました。ビッグエンディアンに依存したコードなので少し面倒でした。

これによりcrt0.sを取り出しました。

crt0.s
crt0    title   unix c library -- runtime initialization
    extrn   main
    extrn   exit
    entry   _exit
r0  equ 0
sp  equ 7
rf  equ 15
    pure
* rearrange args on stack & call main routine
    sis sp,8
    l   r0,8(sp)
    st  r0,0(sp)
    la  r0,12(sp)
    st  r0,4(sp)
    bal rf,main
* if main routine returns, exit
    st  r0,0(sp)
    bal rf,exit
*
_exit   equ *
    l   r0,0(sp)
    svc 14,1
    end

main()が呼ばれるまでを抜粋して、コメントに疑似コードで動作を示します。

    sis sp,8       * sp -= 8
    l   r0,8(sp)   * r0 = *(sp+8)
    st  r0,0(sp)   * argc = r0
    la  r0,12(sp)  * r0 = sp+12
    st  r0,4(sp)   * argv = r0
    bal rf,main    * main(argc, argv)

引数はスタック渡しです。起動直後とmain()が呼ばれる直前のスタックの変化を示します。

アドレス 起動直後 アドレス main直前 備考
0(sp) argc 追記
4(sp) argv 追記
0(sp) argc 8(sp) argc そのまま
4(sp) argv[0] 12(sp) argv[0] そのまま

argcを2つ前にずらしてargvを挿入しています。PDP-11やVAXと違って元のargcを上書きしていません。

V6の移植版のためenvpのサポートはありません。V7の移植版もあるようですが未確認です。

5
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
5
3