UP | HOME

2023年度 システムプログラミング 質問や回答など

今年度の質問など

  • TBA

過去の質問など

第04回 (2022-10-31) でのシートに記入された質問

  1. addiu という命令はありますが,subiu という命令はないのですか
    • subi や subiu はありません.addi, addiu に負に数を与えればいいので.
  2. fact内でさらにfactが呼ばれ続けるときスタックがどんどん確保されると思うのですが, イメージとしては,右図 (省略) のように同じ構造がどんどんできるのでしょうか.
    • はい.そのとおりです.書いてくれている図は,教科書に出ている図そのものですね.

第10回 (2021-12-13) でのシートに記入された質問

  1. 端末から xspim を起動させるときの -maped_io は,プリンタの番地を指定して 出力するときに必要なオプションだと思うのですが,システムプログラミング2では,もう必要ないのでしょうか.
    • システムプログラミング2 では,syscall を使って文字列の出力をしていますから, なくても動きます.while ループで準備ができているかどうかを確認するような ポーリングループを書く場合は, 必要です. 本来 syscall だけを使う場合であっても -maped_io を付けておいて害はない筈ですが, Windows 等で動く QtSPIM では, -maped_io を付けるとまずいようです. (講義ページの「参考資料等」を参照)

第03回 (2021-10-18) でのシートに記入された質問

  1. スクリーンに映るソースコードが見え辛い (11講) 解説のときだけでも照明を一部オフにしていただけると見易くなりそう.
    • どうもありがとうございます.気をつけます.もし忘れていたら,声をかけてくれると助かります.
  2. 2つのプログラムともTAさんに聞きながら,自分で理解しながら完成できた.普通の数字とレジスタに格納されている数字の違いが分かってからスムーズにできた.変数の役割の違いも聞けてよかった.
  3. Practice3 の解答例0で,メイン関数の内の $a0$a1 に置き換えただけでプログラムが動作しなくなりましたが,理由が分かりません.

     1:         .data
     2:         .align 2
     3: msg:    .asciiz "Hello World\n"
     4: 
     5:         .text
     6:         .align 2
     7: main:
     8:         move    $s0, $ra
     9: 
    10:         li      $v0, 4
    11:         la      $a0, msg
    12:         syscall
    13: 
    14:         move    $ra, $s0
    15:         j       $ra
    
    回答

    それは,SPIM の OS では $v0 が実行したいシステムコールの種類を表して $a0 がその引数を表すと決めているからです. それを守らないでそれ以外のレジスタを使うと動かないでしょう.

    これは,C言語の関数の引数の意味と順番は,その関数を作った人が決めていて,それを守らないと動かないのと同様で, つまりその関数が,そう書かれているからです.

    同様に syscall で呼出された先に実行されるであろう print_string のプログラムは, $a0 を使うように作られているわけです. アセンブラには,「何番目の引数」や「関数」という概念がないですから,「何レジスタに入れてジャンプ」という決まりなっているわけです.

    ちなみに,講義でも少し説明しましたが,このような決め事は,OS が違えば異なります.例えば,Linux のプログラムが Windows で動かない理由の一因は, OS のシステムコールに関する決まりが違うからです.

  4. syscall のコードに $v0 を使っていたが, $v1 を使っても意味は変わらないのでしょうか.また, $v0$v1 の 2つを同時に使う場面はありますか.
    回答
    上記の質問と同様に $v1 を使うことはできません. $v0$v1 の 2つを同時に使う場面は,OS がどう決めるかによります.例えば,64bit の値を受渡ししなければいけないような場面がある場合は, $v0$v1 に上位下位の 32ビットづつに分けて受渡しすることも考えられます.
  5. 解答例4では,

            .data
            .align 2
    msg1:   .asciiz "Hello World\n"
    msg2:   .asciiz "int1 -> "
    msg3:   .asciiz "int2 -> "
    

    となっていたが,msg1, msg2, msg3, の各行の後にも .align 2 を導入したときの効率の善し悪し, また,解答例3の

            .data
            .align 2
    msg1:   .asciiz "Number1:"
    msg2:   .asciiz "Number2:"
    msg3:   .asciiz "Answer:"
            .align 2
    

    となっているところ,最後の .align 2 の意味も気になった.

    回答

    確かに解答例3と4で最後の .align 2 の有無が違っていて気持ち悪いですね. .align 2 は,直後に置くデータが 4バイト境界になければならないデータの場合に必要です. 4バイト境界に置かれなければいけないデータというのは,例えば,32ビット整数 (.word) や,その配列です. したがって,それらがのデータの直前に限って .align 2 が必要です.

    ということで,今回の解答例3,4 の .align 2 は,全てなくても動作します (.asciiz しかないので). しかし,安全のために .align 2 を入れておくことは悪いことではないと思います.

    蛇足ですが,解答例4 のように .asciiz の連続のような場合には, 個々の .asciiz の直後に .align 2 を置く必要はありません. .asciiz は,バイト単位で配置されているので,4バイト境界にする必要はないからです. (置いても問題にはなりません)

    解答例3 の最後の .align 2 は,プログラム中の後ろのほうに別の .data を追加してその中に .word を置くときに .align 2 を前置するのを忘れてしまっていても大丈夫にするための予防的な記法と考えることができます. また,解答例3,4 の双方の .data の直後にある .align 2 は,逆にプログラムの前のほうに別の .data を追加した場合や, 前に .word を追加することを考えた予防的な記法ともいえます.

第02回 (2021-10-11) でのシートに記入された質問

  1. 端末での xspim の起動コマンドを間違えて,以下のようにしてしまった.

    xspim & -mapped_io
    

    この問題が 1文字表示のプログラムは起動できるのに,2文字以上の表示では, putc2 の beqz でエラーを起こし,実行不可になることだった. 知らない意味の分かっていないコマンドを打つときは,気を付けたい.

    コメント
    知らないコマンドを実行するときは,その意味を理解するように努めたほうがいいですね. & は,そのコマンドを「バックグラウンド」で動かすという意味で, & の後が別のコマンドと解釈されてしまいますね. その辺りの説明は,1年生のときに使った緑の教科書を読み返してみるといいでしょう.
  2. 解答例の putc サブルーチンの実装で,プリンタに文字をストアするときに sw を用いていましたが,文字は実際には 1バイトなので,sb で動きました.これは,SPIM 側 (プリンタ側) の都合でしょうか.

    1: putc:
    2:         lw      $t0, 0xffff0008         # $t0 = *(0xffff0008)
    3:         li      $t1, 1                  # $t1 = 1
    4:         and     $t0, $t0, $t1           # $t0 &= $t1
    5:         beqz    $t0, putc               # if ($t0 == 0) goto putc
    6:         sw      $a0, 0xffff000c         # *(0xffff000c) = $a0
    7:         j       $ra
    
    回答

    これは,教科書A.8節 「入力と出力」に詳細が書いてあるのですが,今回のケースでは,どちらでも OK です. Transmitter Data Register (0xffff000c 番地に割当てられた印刷用) には 32ビットの領域が割当てられています が, 実際には送られた32ビットデータのうち 最下位8ビット のみを利用してプリントすると記述があるからです.

    ただし,これは,SPIM のバイト順がリトルエンディアンだからです.これは,教科書A.9節 SPIM に簡単に書かれています. 例えば, 0xffff000c 番地から始まる 32ビット に 1を書いて下さいと言われたら,どうなると思いますか.

    こうでしょうか:

    byte-order-be.png

    この場合,最下位8ビットは,ffff000c + 3 つまり ffff000f に位置していますから, sb で 1バイトだけ書くとすれば,, ffff000c ではなく ffff000f に sb するのが正解です.

    このように,8ビット (1バイト) 以上の値を下位の桁に行くにつれて後ろに置く方式の事を ビッグエンディアン 方式といいます.この方式は,桁の小さいほうを後ろに書くので,人間の感覚に近い方式とも言えます.

    一方,SPIM では,リトルエンディアンという,桁の小さい方からメモリに置く方式を採用しています.つまり,こうです:

    byte-order-le.png

    この場合は, 最下位8ビットが先頭,つまり ffff000c に位置していますから,ffff000c に sb で 1 を書いても sw で 1 を書いても 最下位8ビットに1を書いている ことになっていて,SPIM の Transmitter Data Register の仕組みに合致しています.

    以上のことから,sb で動くのは, たまたま SPIM がリトルエンディアン だったからなので, バイト順(エンディアン) のような面倒な事を考慮したくなければ,sw を使うのが正解です.

  3. データとテキストは,C言語でいうところの何にあたるのでしょうか.
    回答
    C言語でいうところの,static 変数を宣言している個所は,プログラム実行前にデータ領域を確保していることになるので,.data の後に .word や .byte を書くのに対応しています. テキストは,プログラムそのものです.

第01回 (2021-10-04) でのシートに記入された質問

  1. また難しい講義が始まったので,生きた心地がしませんでした.
  2. P2-1 (ポーリングによる文字列出力) が分からなかったです.
    コメント
    次回も続きをやるのでお楽しみに
  3. 講義資料の1-1のstepで,if=0 と書いてあるのですが,プログラム的に if=00 でなくてよいのでしょうか.
    回答

    0 も 00 も,この問題の文脈では,同じです. あえて区別したいなら,むしろ if=0 のほうがよいです.

    なぜなら,説明文中で 00 が使われている個所は, 番地 Y を表現する記述として用いられていますが, if=0 で用いられている 0 は,整数値 X に対応する 0 で,別物だからです.

第06回 (2020-11-09) でのシートに記入された質問

  1. sw $a1, 0($a0)0($a0) は,どういうことなのか?
    回答

    これは,C言語でいうと, *($a0 + 0) という意味です.つまり, $a0 番地の中身に $a1 を代入するという意味です. 一方,

    move $a1, $a0
    

    は,

    $a1 = $a0
    

    に相当するので,単に $a1 に $a0 の値そのものを代入するという意味になります.

  2. space 400 で 400 バイト分のメモリを確保していたのに,コードのミスで 404 バイト使用していました.この場合,後ろに更に値が入っていた場合は,侵食したことになるのでしょうか.
    回答
    はい.そうなりますね.試しに space 400 の後に別の .word を置いて,そこが書き変わるのを試してみるといいでしょう.
  3. とりあえずレポートに書くべきプログラム自体は全てできた. while-loop 内の関数引数が変化する際にプログラム自体を少し変更したつもりが大きく変化していたようで,その差を見つけることが難しかった.次回からは,version を変える際は,1つ前の半をしっかり残しておくように心掛けたい.
    コメント
    演習室には,Git というバージョン管理のツールがインストールされています.使いこなせるようになると便利ですよ.
  4. 出題された問題では,課題1-2 が一番説明が難しいく感じた.
    コメント
    これは,実際にステップ実行などで,プログラム動かしながら何が起きているかを観察する必要がありますね.
  5. 課題1.4 は,素数を見付け次第 print.1.5 は, 素数を見付け次第 input 関数によって,配列に組み込むとして,print や input は,独立させていたので,置換することで簡単に実現できた.
    コメント
    input 関数は,どこからでも使えるような関数になっていますか? 引数以外に暗黙の情報共有をしていないように作りましょう.
  6. レポートがきちんと終わるか不安です….がんばれ,来週の自分….
    コメント
    はげますなら,今週の自分のほうがいいと思いますよ.
  7. 毎回の practice の課題で授業中に分からなかったことやできなかったことを次の授業までに復習して仕上げていたので,少しレポートに入りやすかったです.復習は大事だと思いました.
  8. 質問への回答ありがとうございました.参考にしてシステムプログラミング2も頑張りたいと思います.
    コメント
    役に立っているのが分かってよかったです.
  9. 先週動いた practice5-1 のプログラムは,元の C言語のコードを再現できていなかったため,C言語のプログラムと同じ順に処理を進めるように書き直した.これに時間を要したが,配列を採用する practice5-2 は,5-1 の main 部分の終わりの部分を書換えるだけだったので,さほど難しくなかった.
  10. 配列を利用するpractice5-2 の本当の理解ができてうれしかった. レポートを少し進み,時間があれば,プログラムをも少し綺麗にしたい.
  11. 今回の時間で,前回までの疑問点をいくつか解消し,レポートも書き進めることができたのでよかった.ただ,自分自身でアセンブラのプログラミングをすることが難しいので,この一週間である程度知識を定着させ,しっかり試問の対策を取っていきたいと思う.
  12. 解答や解説を見ながら,プログラムの復習をし,理解を深めることができたと思うのでよかったです.
  13. 自力で書くことは難しい.解答例を見て,半分ぐらいは分かった.
  14. すこしづつ書き方に慣れてきている感じがするのでよかったです.
  15. 内容がある程度理解できたので,レポートを書きながらまとめるのが楽しみです.
  16. 配列の作り方は分かった.
  17. 試問に向けてもう一度勉強しなおしたいです.
  18. スタックの概念と Jal (ジャンプ命令) がやっと理解できた.
  19. あまりレポートが手につかなかった.もう一度一番初めの課題から順番に理解して教科書を読み直す必要があると感じた.
  20. practice5-2 の配列への書込みと読み出しがなかなかうまくいかなかったので,試問に向けてアセンブリでの配列についてきちんと復習したい.
  21. $sp のことが少し分かってきた.
  22. 前回あまり理解できていなかった様々な概念を復習することで,理解が進んだ.コードを見てそれを解析し,理科いすることはできるようになったので,プログラムを0から作り出せるようにしたい.また,何かをプログラムによって作るときに,小さな所から少しづつ動作確認して,それらを組み合わせて徐々に大きくしていくという考え方は,これからの開発でも必要不可欠なことなので大切にしたいと思った.
  23. 使ってよいレジスタなどの知識が足りなかったが,今日すべて理解することができた.
  24. 最後のほうの内容が個人的に難しい内容なので,試問までによく理解し,レポートを仕上げたいと思う.
  25. スタックの使い方が分かってきました.レポート作成を通じて,今まで習ったとろを復習しておきたいです.
  26. システムプログラミング1が思った以上に早く終わってしまったので,まだ慣れていないところが多いので,レポートを書きながらできるようになっていきたい.
  27. システムプログラミング2では,C言語か自分で printf が使えるのか,難しいように思えてきた.
  28. 来週は,口頭試問なので,今迄の課題の流れをしっかり復習して試験にのぞむ.また,関数の呼出しのjal命令やスタックについてもう一度復習する.
  29. 今回は,前回の内容を理科いするので,いっぱいいっぱいだった.何とかレポートを間に合わせたい.
  30. 今回,前回できなかった practice5-2 を取り組んだが,1人で作るとなると,未だにミスがるので,もっと理解を深めていきたい.
  31. 今回の講義では,100個の素数を求めて配列に保存するプログラムを作成しました.配列に保存するときにレジスタを使い間違えて最初はうまくプログラムが動きませんでした.プログラムが大きくなると使うレジスタやスタックが増えてきて混乱することが多くなりましたが,ここの管理を上手にできるように気をつけていきたいと思いました.
  32. 今回でレポートを書き始めた.今迄やってきたことをもう一度学び直すことによって定着させたい.
  33. レポートを書くにあたって,過去に自分がプログラムを書く際に考えていたことや,自分がプログラムを書くにあたって,でききれなかった部分,逆にできた部分等を細かに思い出してゆく必要がある.
  34. 試問までにレポートが間に合うか不安.
  35. レジスタ1個1個の役割を理解しておく.
  36. 配列の仕組みがまだ理解できていなかったので復習しておく.
  37. レポートも試問も詰め込まないと厳しそうなので,1週間頑張ろうと思います.
  38. 何とか期末レポートの課題プログラムは,完成させることができた.来週の試問に向けて復習,ポート作成に注力する.
  39. .text.data といった基本的なアセンブラ指令をあまり理解せずに進めていて,今回のレポート課題をきっかけに TAの方に質問したり,理解を深めることができた.
  40. 講義中にレポートのためのプログラムは何とか作ることができたが,まだ理解が甘いところがあるので,試問日までに講義資料を勉強しなおして,レポートにまとめるようにしたい.
  41. レポート作成に向けてプログラムを完成させることができたので,それらについての考察を十分に深め,良いレポートが記述できるように務める.

第05回 (2020-11-02) でのシートに記入された質問

  1. 配列の扱いについて,これを頭の中で整理しながら MIPS を書くのは難しかったため,メモとして図を描きながらプログラムした.
  2. 今回の講義 (中略) 最初は,戻り先のアドレスが格納されているレジスタをスタックに入れずにプログラムを作成していたため,変なケアレスミスをしてしまい,うまく出来ませんでした. それで,過去の授業の内容を読み直し,スタックを作ってみると,ミスなくうまく作成することができた.これからは,スタックをよく考えようと思った.
  3. practice5-1 で stack を使わずにプログラムを作ることができたが,今一スタックの使い方が分からない
    回答
    うまく書くと stack を使わないで書けることもあります. fact 関数のように $ra$ レジスタや $a0 を保存したりする領域を必要とすることが多いです.
  4. おすすめの勉強法などあれば,教えてください.
    回答
    プログラミング全般に言えることですが,とにかく短かいプログラムで動作確認をこまめにすることです.いきなり完成形を作るのではなく.
    • 例えば, test_prime を作るとして,いきなり書き上げるのではなく,割った余りを表示するだけのプログラムを作るところからはじめます.
    • また,print_intprint_stirng をプログラム中のいたるところに挿入して表示させるのを 簡単にできる ようにしておきましょう. そのためには,手続き呼出し規約にのっとった, print_int のようなプログラムを常に使えるようにしておくことです.
  5. どこを間違えているのかすばやく探すコツが知りたいです.
    回答
    いくつかあると思います.
    • 自分のためにコメントを書く.アセンブラは1つ1つの命令でできることが限られているので,何個かの命令で C言語の1命令に相当することが多いです. そういう対訳をコメントとして書きましょう.また C言語の文単位ぐらいで空行を入れてやると理解しやすくなります.
    • できるだけ新規にプログラムを書かないようにしましょう.動くことが分かっている小さな部品(関数) を組み合わせてプログラムを作りましょう.
      • たとえば, $v0 に値を入れて syscall を呼ぶのではなく,以前定義した print_string や read_int を使い回しましょう.
    • 一度に大きなプログラムを動かさないようにしましょう.
      • 例えば, test_prime ができたと思ったら,単体で動作確認のテストプログラムを書きましょう.今回の main 関数は, test_prime に比べても複雑です.
      • 私なら,まず test_prime を 愚直に引数 ($a0) を変えてループなど作らずに素直に 5回だけ実行する main を作ります. (hello を putc 5回呼ぶことで作りましたよね)
  6. 関数という概念をしっかり理解していなかった.また,以下の場合関数と呼べるのか.
    回答
    図付きで書いてくれていましたが,呼べると思います.C言語と同じように考えてください. 例えば,test_prime は関数であるためには,
    1. x行目からy行目までの一連の行でできている (飛び地がない).
    2. x行名 (関数の先頭) 以外の行に関数外 (x行目-y行目以外) からジャンプしているようなカ所がない.
    3. 外からは,必ず jal でしか呼ばれない.
    4. 終了時は,かならず j $ra で終了する.
  7. レジスタの使い分けがよく分からないです. $t0-$t9$v0-$v1 では, 自分の理解では,どちらも別に壊されてもよい変数として使ってよくて,$a0 は壊されたくないものを使うという理解をしていますが.
    回答
    いいえ.どちらも $a0-$a3 も関数の中で壊してもよいレジスタです. what-is-calling-convention.html にある通りです.ここで気を付けなければいけないのは,関数の中で壊されてもよい変数として使ってよいということは,
    • 呼出される側を主体に取ると,「自由に書換えてよい」という意味ですが
    • 呼出し側を主体で見ると,「壊れる恐れがあるレジスタ」という意味です.
  8. 今回の内容も非常に難解だった.とても TA への質問なしにはできる気がしない.
    コメント
    そのための TA ですから,よく質問してあげてください.それと今年度の皆さんは, C言語 (ポインタ回り) の理解が不十分なことが,アセンブラを理解しづらい原因の1つになっているような気がします. プログラミング演習の内容を復習してみることも1つの方法だと思います.
  9. j と jr と jal の違いがよく分かりません.
    回答
    jal は,演習問題としても皆さんに提出してもらって,既出なので講義資料をよく読み換えしてもらうとして,j と jr は 過去の質問にもあるので,読んでみてください.
  10. main 関数では,分岐命令より後ろにあるラベルへ分岐できませんが…
    回答
    そんなことはありません
  11. .space 400 は,実行ファイルのバイナリにもこの400バイトが空白で入っているのでしょうか
    回答
    そんなことはりませ.具体的には,シンボルとその大きさだけが入っていて,BSS 領域に確保されてから,main 関数が呼ばれます.
  12. 前回の内容を復習しても自分で回答の意味を理解できず,TAさんに教えていただけたので助かりました.
  13. 元々のC言語のプログラムを理解しきらずに作成しようとしたのでうまくいかなかった.
  14. レジスタの使い分けがうまくできない $t0 がよく分からない.
  15. test_primemain の違いがあまり分からない.
    コメント
    どう見ても違うと思うのですが.
  16. スタックの利用が難しいです.習ったないよう の応用難しいです.
  17. lw, la の違いが詳しく分かりません.
    回答
    lw じゃなくて, li じゃないでしょうか.これは,FAQ に載っているので,参考にしてください.
  18. スタックを作るべき部分がまだよく分からない.
    • 関数の開始と終了において全てです.
  19. Cでは,10分で書けた素数のプログラムが 3時間あっても終わらなかった.原因は戻り値だと思うので,理解を深めておきたい.
  20. どのレジスタがどこに使うべきかを覚えていないので,紙に書きながらレジスタの表を見るのを繰り返す必要があり,ものすごく時間がかかった.
  21. 自分でコードを書き進めることがまだ全然できないです.理解できていないことばかりで,復習で何とかしたいです.
  22. 配列の考え方は,前回の SP を使うものより理解しやすかった
  23. 難しかったです
  24. loop 関数から main に戻るためにスタックが必要だという考えが思い浮かばなかった.
  25. 最初は,素数の判定を1つづつ割り算の余りを求めてから判定していこうと思ったが,途中でスタックでやった方が良いと言われ,やり方を変えようとしたが,最後まで書くことができなかった.
  26. どこからどこまでが関数なのかをあまり意識せずにプログラムを書いてしまったので,プログラムを書き直したい.

第04回 (2020-10-26) でのシートに記入された質問

fp の話

  1. 感想: fp の使い方がいまいちよく分からなかった.
  2. 質問: スタックポインタは分かりましたが,フレームポインタが分かりません.
  3. 確保したスタックの上限下限を決めているのが,SP, FP という認識でいいですか.
  4. スタックポインタは,理解できたが,フレームポインタは理解できなかった.今日の授業内で課題が終わらなかったが,方針が立ったので,次回までに終わらせておく.
  5. 教科書の例は分かったが,自分で書こうとしたら,全然わからなかった.再帰の様子を分かりやすくイメージしたいが,なかなかできない.また,fp が何なのかいまだにいまいに分からない.
    回答
    はい. fp を使う意味については,質問2 に詳しく書いてあります.
  6. 0($fp) の記法がよく分からない.
    回答
    C言語的に書くと,20($fp) は, *($fp + 20) という意味です. 0($fp) は *($fp) と同じですね.

その他

  1. だいぶ考えた結果,ループがどのように動くのか理解できました.
  2. 処理を行うたびに新しい領域を確保して,のちに使うアドレスを保存しておき,戻ることになるときれにそれを回収していくプログラムと分かると,とても気持ちがよかった.
  3. ホームページの解説を理解するのに時間がかかってしまい,講義時間内に終わることができなかった.頭がこんがらがって訳が分からなくなりそうなので,家で落ち着いて考えなおそうと思う.
    回答
    受講生の中には「後でしっかり復習したい」というような感想を持つ人が多かったようです. 復習も大事ですが,もう1つおすすめは,事前の予習です.講義資料を一読して事前に何をしっかり聞くべきかを見ておくだけでも,効率がよいのでおすすめです.
  4. レジスタの退避と復帰を全ての関数に書くのは面倒なので,それ自体を関数にはできないのでしょうか.
    回答
    その関数の退避と復帰を書かないといけなくならないですか.
  5. MIPS においては,for分と再帰呼出しで fact を実装すると,どちらが短時間で実行できますか.
    回答
    それは,単純に実行すべき命令数が多いか少ないかで決まります.単一のループだと SP の操作が減るため,通常は for で書くほうが速いです. なので言語によっては,再帰をループに最適化する機能があります.「末尾再帰の最適化」で検索してみるといいでしょう.
  6. $L1 や $L2 など,教科書が何回でなかなか理解できなかった.
    回答
    $L1 や $L2 も単なるラベルで,他のものと変わりはありません.すくなくともこの講義の範囲内では.
  7. スタックの確保が,32バイト,ra の確保が 20バイト目,sp が 16バイト目の,32, 20, 16 という刻みには,何か意味があるのでしょうか.
    回答
    はい. 質問4 にあるように,Practice 6 で説明しています.
  8. jr と j の違い,u が付くときと付かないときの違い,ロード命令とストア命令の違い,復元やポップについて分かっていないので,復習します.
    回答
    jr/j や addu/add の違いは,過去の質問の中に書いてあるので参考にしてください. POP とは,スタックポインタを復元することと同義です.スタックの操作を push/pop といいますが,これは,「データ構造とアルゴリズム」で習う筈です. ロード命令とストア命令は,本講義の最初のスライドに書いてあります.
  1. 再帰呼出し関数は,スタックを掘り下げてデータを格納し,最後にデータをlw するこが必要だと分かったが,理解が追い付かないので,復習をがんばりたいです.
    回答
    掘り下げてというより,スタックなので積上げてのほうがしっくりきますね.
  2. 手続き呼出しのプログラムは,今までのものに比べて,かなり難しく感じた.過程をもっと図に表したものがあれば理解しやすくなるかなと思う.
    回答
    自分で作図してみることを勧めます.
  3. Cで書くと何となく分かっていたことが,アセンブラで書くと分からなかった.普段から詳しく分かっておく必要性を感じたし,Cがどれだけ人間に優しい言語であるか分かった.
    回答
    Cも結構厳しい言語ではあるのですけどね.でも「評価 (evaluation)」とは何かという考え方は,重要で,どの言語でもしばしば問題になります.
  4. 再帰呼出しのイメージはできるが,実際に作るのはかなり難しいと感じた.
    回答
    むしろ,作るのは,機械的にできますが,イメージするのは難しいのではないでしょうか.書けても説明できない人はいても逆はないと思います.
  5. やはり,アセンブリ言語を扱うのは難しい.高級言語である C言語などとは違い,アセンブリ言語は行われている,行うことがイメージし辛い.
    回答
    こうも言えるかもしれません. 「C言語では,アセンブラと違い,中で行われていることがイメージしつらい.なぜなら,アセンブラは書いた通り動いているが,C言語は,コンパイラが出力したアセンブラを想像しなければならないから.」
  6. 今回のプログラムをC言語で書かれたものにしようと考えると,変数の起き方やかけ算のしかた,条件文の置きかたなどをしっかり考えなければならないと思いました. 計算結果自体は,出すことができましたが,課題のソースコードをアセンブリ言語に変換したものとは違うと思ったので,変換するというのは,かなり骨が折れるものだと思いました. また,今回の課題の内容だと,レジスタだけを使ってもコードは書けたのですが,やはりそれでは,逆コンパイルすると同じものにはならないのか,また再帰ではないのかということがいまいち分かりませんでした.
  7. 今回の内容が今までのシステムプログラミングの中で一番難しかった.最初に作成したプログラムも,loop のような状況だったので,次は再帰関数のようにできるプログラム方法で作成したい.
  8. 今回は,手続き呼出しについて学んだ.今回の授業が一番難しく,理解するのに困難だった.呼び出しの置こる流れを考えられるようにする.
  9. スタックの確保と解放の手続きを使うことで新たな領域の使用ができるようになったので,応用していきたいと思った.
  10. 今回の講義では,手続き呼出し規約について学び,再帰呼出しを使った階乗を作成しました.最初は解説を見ることなく,自力で作ったため,再帰呼出しではなく, fact -1 を新たに作り,その中からジャンプ命令で fact を行うプログラムを作っていました. その後,先生の解説を聞き,改めて再帰呼出しを理解して今度は fact 関数内で判別を行い,自力で fact 関数をよびだして再帰構造を作ることができました. スタックについては,これから先プログラムを作る上で,関数が多く必要なときに有効に活用していこうと思いました.
  11. 再帰構造がちゃんと理解できていなかったので,ループするだけのものができあがった.
  12. スタックがどんどんたまっていって,最後に fact(1) の計算,fact(2) の計算… fact(10) の計算をして消費して v0 に値を入れて main に持って帰る プログラムの流れを追うのがとても難しかった.
  13. メモリの解放したときに戻すのを忘れそうなので,気をつけたい.C言語よりも,再帰関数の中身がややこしかった.
  14. 再帰構造をアセンブラ言語に表記しなおすことに慣れておらず,はじめはとまどった.なんとか理解することができたので,忘れないうちによく復習しておきたい.
  15. きちんと動かなかったので,原因を突き止めたいです.前回の授業で分からなかったころが理解できてよかったです.試問に向けて分からないところは,ちゃんと学んでいきたいです.
  16. スタックを用い,$ra や他のレジスタの内容を保存する方法は分かった.C言語だたお,再帰構造の方がシンプルになるコードが,アセンブラだとむしろ長くなるのが面白かった.jal 命令が複数行われるようになると,$ra がどこを指しているのか分からなくなり混乱した.
  17. 最初に自分で解説や教科書を見てもスタックポインタについてよく分からなかったが,先生の説明や自分なりに教科書の内容を噛み砕くことで,イメージはなんとなく掴むことができたとおもう. 手続き呼出し規約についても,今後重要になってくる内容だと感じたので,復習等でより理解を深めたい.
  18. スタックの確保の利点やスタック内へのデータ退避の方法などを理解するのに時間はかかったが,理解できれば以外と単純な構造をしていると感じた.
    回答
    そうですね,実は理にかなっていてシンプルで,自転車に乗るように一旦体得すると,なぜで(理解)きなかったのが分からなくなると思います.
  19. 初めは,fact関数を作る際に,$s0-$s3 を保存領域として使用してループによって計算は実現しました. その後,スタックによる退避によるプログラムを考えました.まだ自分の中で再帰呼出しの定義があまりはっきりしないので,自分の中で理解したいと思っています.
  20. 感想: 理解が足りていないことが分かった.無限ループしている.
  21. 感想: 難しかった!
  22. 感想: 再帰呼出しの原則である,先に次々と呼出して,一番最後に呼出したものの値が出てから順に戻るように計算するということを忘れていたので苦戦した.
  23. 感想: 同じ $a0 でもスタックを別に取れば,利用することができた.
  24. 感想: 今迄感覚的に捉えていた再帰呼び出し処理についての理解が深まったように思いました.
  25. 感想: 何段もの fact を呼出した後,そこから元の手続きに戻るのは難しと思った.
  26. 感想: fact 関数を実装するのにどうすればよいか分からなかったので,最初はループを使っていた.その後,先生の解説を聞いて,スタックを使って再帰呼出しで実装できた.
  27. レジスタの仕様規約とスタックの退避と復帰に関しては,教科書を見つつ何となく理解できたが,実際に関数を実装する場合,どう書けばいいのか正直よく分からなかった.
  28. ループした後にループするという考えに驚いた.C言語的な考えにとらわれていた.かけ算のループがしっかり理解できたとはいえない.
  29. 教科書にある fact 関数を見たときに,最初どのように動いているのかが,よく分かりませんでした.
  30. 初め,ループ処理を用いて fact() を実装してしまったが,後の再帰呼出しで書いて比較してみると,その違いがよく分かると共に,スタックを理解することができた.
  31. 前回と比べて,構造が少し複雑になり,まだ理解できていない部分も多いので,復習して次回までに分かるようにしておきます.

第03回 (2020-10-19) でのシートに記入された質問

  1. 感想: 専門用語やアセンブラのルールを覚えらおらず,practice を時間内に解くことができなかったのが悔しい.次はヒントを元に解けるように頑張りたい.
  2. 感想: 高級言語でソースコードを書くよりも許可を得たり使えるかどうかなど少しアセンブリ言語は技巧的のように思えた.

第02回 (2020-10-12) でのシートに記入された質問

  1. 感想: 解答例が公開されるまで,分からなかったけど,例を読んで理解することはできたので,試問までにもっと理解を深めて自力でプログラムが書けるようにしたい.
  2. 感想: MIPS命令について,多くあるので実際に使いながら理解していきたいと思います.
  3. 感想: C言語では,printf を使ったら何回も関数呼出したりせずに日本 語でも英語でもすぐに画面に出力できたけど,アセンブリでは,今自分 が何をしているのか $ra の中にはどこのアドレスがなど色々なことを考 えないといけないし,文字を出力するにもコンピュータに聞かないとで きないなど,かなり理解にしくいと思いました.ひとつひとつの命令が しっかり理解できていないとデータをコピーするだけでも一苦労だと思 いました.
  4. 質問: Practice2-1 の「Hello」を表示させるプログラムで 「putc」 という関数を jal 命令で 5回呼出す方針で勧めたところ,無限ループに陥ってしまったため,最後の 「o」 以外の時は, jal 命令で呼出し, j $ra で戻る putc1 関数と 「o」のときは j 命令で呼出し戻るという操作をしない関数 「putc2」 を作りました. そうすると,Hello が表示されましたが,問題はないでしょうか.また,分岐命令を用いることで,putc 1つで無限ループに入らないようにすることは可能ですか.
    回答

    実際のコードを見せてもらえると,もっといいアドバイスができると思いますが,おそらく putX を複数作る時点で悪手だと思います.「最後だけは」といった仮定や (それが最後かどうかは,プログラムの都合でいつも変わります) 戻るという操作をしないというのは,では,具体的にどういう操作を代わりにするのでしょうか.戻る操作をしないでプログラムの実行が下に流れて行くのに任せるとプログラムが暴走してしまいそうです. 特定の番地に戻るということを仮定してしまうと,それは,main ではないところから呼べなくなってしまいます.

    関数は,入口と出口の形式 (インタフェース) を統一することでいつも同じ形で呼出しできるプログラムになっていないといけません.

第01回 (2020-10-05) でのシートに記入された質問

  1. 感想: 始めは難しいと思ったが,C言語に置き換えて考えると理解しやすいと思った.
  2. アセンブリ言語でゲームを作っていた時代もあったのでしょうか.
    回答

    はい.スーパーマリオの時代のゲームは,ほぼそうだと思います. セガの開発技術部のブログの記事が面白いかもしれません.

    アセンブリ言語: 最も原始的でハードウェアに近い言語で ある アセンブリ言語 は、大きなプログラムを書くことに は向いていませんが、特に高速に処理を行いたい部分にピ ンポイントに利用されています。

  3. CPU によって命令セットが違うのなら,コンパイラは,CPUごとに命令セットを知っておく必要があるのですか.
    回答
    はい.その通りです.例えば,演習室の gcc は,C言語から Intel の CPU (x86 という) の命令セットを出力するコンパイラです. SPIM 用には,spim-gcc というコンパイラを用意しています.そのコンパイラが動くCPUとは別のCPUのためのコンパイラをクロスコンパイラと呼びます.

第05回 (2019-11-11) でのシートに記入された質問

  1. データセグメントとテキストセグメントの差があまり分からないです.
    回答
    データセグメントにはデータが,テキストセグメントにはプログラム (テキスト)が置かれる.詳細な説明に関しては,Practice2-3 の解説で述べている.
  2. $a,$v,$s の上手な置き方を知りたいです.
    回答
    手続き呼び出し規約に基づいておけば問題ありません.具体的にどう困っているのでしょうか.「上手」の基準が不明確です.
  3. Practice4 の printf 実装した解答例が欲しいです.
    回答
    printf は,システムプログラミング2 で実際に実装するべき大きな課題で,現時点で printf を実際に使ったプログラムを動作させることは難しいでしょう. 教科書の解答例は,あくまでも printf が既にあると仮定しての解答例です.実際には,printf 相当を print_stringprint_int システムコールで代替する必要があります. それを示したものが 解答例2 です.
  4. Practice4 の解答で fact内だけでなく,main 内でもスタックを確保している のはなぜですか.main 内でスタックを使用しているのは,戻り先のアドレ スを退避するためだけなので戻り先のアドレスを $s0 などに退避してしまえ ばスタックを確保する必要はないように思えるのですが,何がメリットですか.
    回答
    main 自身も呼ばれる立場の関数なので,そもそも main 中で $s0 を使用する場合,事前に値を退避する必要があります. つまり,いずれにしても main 関数でスタックを確保しなければなりません.
  5. レポートについて,ラベル名は数式モードで表示すべきですか.
    回答
    数式モードではなく,プログラム中のシンボルは,verb コマンドを用いて下さい.

第04回 (2019-11-07) でのシートに記入された質問

  1. $fp と $spの違いがよくわかりません.
    回答
    $spは,スタック最上位アドレス(つまり,メモリをどこまで使ったか) を示すレジスタです.$fpは,スタック最下位アドレス(つまり,メモリをどこから使ったか)を示すレジスタです.
  2. アセンブラはかなり多くの書き方がある気がしますが正解のようなものってあるのですか.
    回答
    アセンブラでなくとも,プログラミングは,正解が1つではありません. 手続き呼び出し規約に基づいた記法に従った上で,いい方法を考えてください.
  3. .rdataとは何ですか.
    回答
    講義でも説明しましたが,.rdata は,読み出し専用のデータセグメントを指します. 定数データは,書換える必要がないので,他と区別することがあります. そうすることで,ROM に配置したりできるからです.
  4. .globl main とは何ですか
    回答
    .globl main は,mainが外部から参照可能になることを示しています. 複数のファイルでプログラムを作った場合に,そのシンボルが他のファイル中から参照できるかどうかを指定します. 今回の演習では,気にしなくても問題ありません.

第03回 (2019-10-28) でのシートに記入された質問

  1. Practice3の解答例1において,以下の記述があった.

    move $s0, $ra
    ...(中略)...
    move $ra, $s0
    

    この2行を省いた場合でも結果が変わらなかったのだが,これは必要なのか.

    回答
    現時点までの講義内容からでは,システムコールが $ra を書き換えな いという保証はない.このため,システムコールを呼ぶ前に $ra の値 を退避させている.実際には,システムコールで $ra の値が書き換え られることはないため,上記の記述を省いた場合でも結果は変わらない.
  2. レジスタにシステムコールの read_int で標準入力から値を受け取る際に,代入先のレジスタは初期化しなくても良いのか.
    回答
    read_int の場合,代入先のレジスタは $v0 で,それにはシステムコール番号が入っているため,関係ない. 初期化というのは,使用する前に不定な値が入っている状態にならないために必要なので,この場合には,それにあたらない.
  3. スタックポインタの利用方法の具体例が知りたいです.
    回答
    スタックポインタは,新たにスタックを確保した際に,どの領域が利用 可能かを示すために用いられる.詳細に関しては,Practice4-1 の解説に記載されている.
  4. レポートの形式について知りたいです.
    回答
    講義のページ中に記載がある.以下のページにレポートの書き方が記載されているため参考にすると良い. http://www.swlab.cs.okayama-u.ac.jp/~nom/lect/common/report.html
  5. j命令と jr 命令の違いを教えてください.
    回答
    j 命令はオペランドがラベルであるのに対して,jr 命令はオペランドがレジスタである. ただし,SPIMでは,j 命令のオペランドがレジスタであっても,アセンブラが読み換えてくれるので,講義中では区別されていない.
  1. add 命令の末尾に「u」を付けている Webページがいくつかあったのですが,何か意味があるのでしょうか.
    回答
    add 命令が符号有りの加算であるのに対して,addu 命令は,符号なし,あるいはオーバーフローなしの加算である. つまり,nビットの整数 2のn上-1 を -1 と見るか,そのまま 2のn乗 -1 と見るかが異なる.
  1. add や addi,sub 命令はあるのに,subi 命令がないのはなぜか.
    回答
    減算は負の数の加算と同じであるので,単純化のために MIPS には subi 命令は存在しない.
  2. .byte について,

    .byte 72,110,0
    .byte 72, 110, 0
    

    前者では動かず,後者では動いた.「,」の後のスペースはプログラムの挙 動に関係しているのか.

    回答
    演習室の xspim では,.byte において,「,」の後のスペースがないと,Syntax Error となるようです.

Author: Yoshinari Nomura

Emacs 27.1 (Org mode 9.3)