低レベルプログラミング・問題解答

投稿日: 更新日:

本記事は『低レベルプログラミング』(翔泳社)の問題に対する、私自身の解答メモです。正解の保証はありません。正式な解答は著者の公式GitHubを参照してください: https://github.com/Apress/low-level-programming

参考文献
Igor Zhirkov(著),吉川邦夫(訳・監修)『低レベルプログラミング』翔泳社,2018年.ISBN:978-4-7981-5503-6. 公式ページ:https://www.shoeisha.co.jp/book/detail/9784798155036 (最終アクセス:2025-08-02)

解いたら更新します。

問題1(p. 15)

  • CF : Carry flag・最上位ビットがキャリーかボローが発生した場合にセットされ、それ以外はクリアされるされるフラグ
  • AF : Auxiliary Carry flag・3ビット目からキャリーかボローが発生した場合にセットされ、それ以外はクリアされるフラグ
  • ZF : Zero flag・結果が0の場合にセットされそれ以外はクリアされるフラグ
  • OF : 演算結果がオペランドに収まりきらないほど大きな正の整数もしくは小さな負の整数である場合にセットされそれ以外はクリアされるフラグ
  • SF : 符号つき整数で符号を示す最上位ビットと同じ値になる。0は正、1は負

OFとCFの違いはOFは符号付き整数、CFは符号なし整数での結果を示す。

問題2(p.20)

  • メモリに命令列とデータの両方が保存されそれを区別する手段はない
  • 命令の実行はジャンプ命令を使用しない限りシーケンシャルに実行される

問題3(p.20)

プロセッサ自身が持つメモリセルのこと。応答時間が高速で通常はCPUサイクル2つに等しい。

問題4(p.20)

LIFOのデータ構造。push命令とpop命令と1つのレジスタ(rsp)によって構成される。専用のメモリがあるわけではなく、データは既存のメモリに保存される。

問題5(p.20)

外部イベントを基準として、プログラムの実行順序を変更すること。

問題6(p.20)

遅いメモリの問い合わせをレジスタ、キャッシュで解決。対話性を割り込みで解決。コードを隔離するためのサポートをハードウェアスタックで実装。 プログラムが実行できる命令をプロテクションリングで制限。プログラムを互いに隔離するために仮想メモリを実装。

問題7(p.20)

  • rax (r0) accumulatorとして算術演算で使われる
  • rcx (r1) ループの回数(cycles)に使われる
  • rdx (r2) 入出力処理の間、データを格納する
  • rbx (r3) ベースレジスタ
  • rsp (r4) スタックポインタ
  • rbp (r5) スタックフレームのベースポインタ
  • rsi (r6) ストリング操作コマンドのソース側インデックス
  • rdi (r7) ストリング操作コマンドのデスティネーション側インデックス
  • r8~r15

問題8(p.20)

スタックの次に書き込まれるアドレス、別のアーキテクチャでは最後の要素をさす。

問題9(p.20)

ならない。一回もpushしていなくてもスタックポインタがさすアドレスの内容が返される。

問題10(p.20)

数えられない。popはpush回数に関係なく実行できるし、スタックがどこから始まっているかを知ることはできないため。

問題11 (p.28)

  • xor : 排他的理論和をとる命令。xor dest src でdestとsrcの演算結果をdestに格納する。

xor rdi, rdi はrdi ^ rdiを取るのでrdiに0をセットするのと同じ。

問題12 (p.28)

ridが0にセットされているので0

問題13 (p.28)

プログラムのリターンコード。

問題14 (p.29)

mov rax, 0x0123456789ABCDEFと書き換えてちゃんと0123456789ABCDEFとでたので問題なさそう。

問題15 (p.29)

sarもshrも右シフトの処理だが、sarはshift arithmetic right(算術右シフト)で最上位ビットを符号が合うようにセットする。 shrはshift logical rightで最上位ビットは0にセットされる。

問題16 (p.29)

  • 2進数は末尾にbかyを付けるか、接頭辞に0bか0yを付ける。
  • 8進数は末尾にqかoを付けるか、接頭辞に0oか0qを付ける。
  • 16進数は末尾にh、接頭辞に0xか0hを付ける。

問題17 (p.32)

jz、jeどちらもZFが1の時にジャンプするので違いはない。

問題18 (p.39)

最初、testに-1が書き込まれているから全てF。そこからリトルエンディアンで値を書き込めばよい。

  1. 0x01_FF_FF_FF_FF_FF_FF_FF
  2. 0x01_00_FF_FF_FF_FF_FF_FF
  3. 0x01_00_00_00_FF_FF_FF_FF
  4. 0x01_00_00_00_00_00_00_00

問題19 (p.42)

r13が初期化されていない事。また、初期化前にr13の値を退避し、ret前に戻す必要がある。

問題45 (p.54)

インデックスが1、テーブルインジケータが0なのでGDT、要求特権レベルは0なので最高。

問題46 (p.58)

マクロコード:CPU内部である命令を実行するために必要な命令群

パイプライン:読み込み、解読、実行の命令を並列して行うこと

問題47 (p.65)

  • FIFO: 最初に割り当てた(最も古い)ページを置換する
  • LIFO: 最後に割り当てた(最も新しい)ページを置換する

問題48 (p.67)

4番目のコラムは、メジャー番号:マイナー番号

5番目のコラムはiノード番号

問題49 (p.68)

アソシアティブキャッシュ:メモリのどこでもデータを自由に格納できる方式。 TLBがアドレスを変換してくれるので論理アドレスのどこへでも格納できる。

問題50 (p.77)

アドレスがページサイズの倍数から始まり、すべてのページが同じパーミッションを持つこと。

問題51 (p.77)

読み込み専用なのでSegmentation faultとエラーがでる。

問題52 (p.77)

値が定義されておらずアクセスするとエラーが発生する。

問題53 (p.77)

仮想アドレスの構造を満たすもの。上位17ビットが全部同じという性質がある。

問題54 (p.77)

仮想アドレスを物理アドレスに変換するテーブルである。PML4、ページディレクトリポンタテーブル、ページディレクトリ、ページテーブルからなる。

問題55 (p.77)

物理アドレス空間が仮想ページを割り当てるのに分割されていて、これらのスロットのこと。

問題56 (p.77)

アドレスがページサイズの倍数から始まり、すべてのページが同じパーミッションを持つこと。

問題57 (p.77)

仮想アドレス空間はプロセスごとに作成され、任意のサイズを確保でき、メモリのどこでも置くことができる。

問題58 (p.77)

仮想メモリのアクセスを高速化するためのキャッシュ。これにより毎回テーブルを見る必要が無くなる。

問題59 (p.78)

TLBによってキャッシュされるから。局所性のおかげでページを追加でロードする必要が滅多にないから。

問題60 (p.78)

物理アドレスと論理アドレスを変換するのはMMU(Memory Management Unit)で行われる。

問題61 (p.78)

無効なアドレスへのアクセスはエラーが発生すること。パーミッションが割り当てられること。

問題62 (p.78)

悪意ある命令をスタックやデータセクションに書き込まれたとしてもEXBで実行禁止とマークされていれば阻止できるから。

問題63 (p.78)

6348はbit47を繰り返している。4739はページマップテーブルのインデックス。3830はページディレクトリテーブルのインデックス。2921はページディレクトリのインデックス。2012はページテーブルのインデックス。110はページ先頭からのオフセット。

問題64 (p.78)

共通部分はどちらもページ単位で管理されること。

問題65 (p.78)

書けるが、読み込み専用なので上書きはできない。

書いた人

profile_image

お茶の葉

物理とプログラミングが好きな人