<< 2024-07-21のCコンパイラゼミ | Cコンパイラゼミ2024 | セキュリティキャンプ2024 2日目のCコンパイラゼミ >>

やるぞやるぞ

self2-mainのセグフォを何とかする

  • self2-mainとは、main.cだけ第一世代コンパイラ、その他のファイルをGCCでコンパイルした場合のテスト
  • node_kinds[i++]というコードにおいて、可算代入の際にiは4バイト分しか確保してないのにも関わらず、8バイト分の数値を読み出して加算していたためセグフォが起きていた
  • 型に合わせて取り出すバイト数を変える処理を入れて解決

self2-mainの関数も変数も出力されないのを何とかする

  • read_fileでファイルの文字列が読み込まれないのが原因で、なぜかと言うとftellで0が返ってきていた
  • 調査した結果、fseekの引数にグローバル変数SEEK_ENDを使っていたが、SEEK_ENDの値が0になっていた
  • なぜかというと、グローバル変数の初期化式を実装していなかった
    • 実装していない部分はエラーを表示するようにしていたが、今回はそこから抜けていた
      • グローバル変数を実装したときは0クリアしていて、
      • さらに初期化式を実装したときにはグローバル変数のことを忘れていた
  • グローバル変数の初期化式を実装して上手く動くようになった
  • 1時間調査した結果が「単に未実装箇所を踏んでいた」ってのは辛いよぉー・・・

whileの入ったファイルをself2-analyzeでコンパイルするとセグフォする

  • self2-analyzeとは、analyze.cだけ第一世代コンパイラ、その他のファイルをGCCでコンパイルした場合のテスト

  • self2-analyzeにwhile文の入ったファイルを入れるとセグフォする

  • while文を解析する部分のcallocで取得した部分のアドレスがやけに短い

    • 0x4ad800、文字列リテラルのアドレスと同じ長さ。短すぎる
  • なので、callocの呼び出しがおかしそう

  • けれど、アセンブリを見た限り変な箇所はない

  • 色々疑った結果、16バイトアライメントが悪いのではないかということになり、16バイトアライメントを実装した

  • けれど、結果は変わらずcallocのアドレスは短いまま

  • さらに試すと、ローカル変数があるときに16バイトアライメントがずれることが分かったので直すも、結果は変わらず

  • 第一世代でそのまま動かした場合

    • 7桁-8桁
    • 0x3153e800
  • 第一世代でgdbを使った場合

    • 0x4ad800で固定(6桁)
  • gccでそのまま動かした場合

    • 12桁
    • 0x594ee070f2a0
  • gccとgdbの場合

    • 0x5555555592a0で固定(12桁)
  • CompilerExplorerが出したアセンブリ(ディレクティブ含む)を実行した場合

    • 7桁-8桁
    • 0x2abb6800
  • gccで一旦アセンブリを出して、それをバイナリにした場合

    • 7桁-8桁
    • 0x32dc6800

これを考えると、アセンブラを通すと8桁になると考える他なさそう。謎すぎる。 callocをmallocに変えても特に変化は起きず。

アドレスの長さ

x86_64でLinuxだと、ポインタのアドレスは以下のような性質がある。

  • ヒープメモリは48ビット、16進で12文字の長さ
    • 64ビットアドレスとか言うけれど、現在は48ビットしか使われていない
  • 文字列リテラルなんかのアドレスは16進で6文字の長さ

文字列リテラルのsizeof

  • 文字列リテラルの型をchar*にしてた気がする