banner
yono

yono

哈喽~欢迎光临
follow
github

なぜ MicroLib と printf を使わないのか —— Arm の Semihosting

結論#

結論は前に書かれています

  1. まず、microLib を使用しない理由は、ソースコードの挙動を制御可能にするためであり、ベンダーの不適切な行為によってソース lib が変更されることはありません。また、ソースコードはクロスプラットフォームの能力を持ち、C 標準ライブラリの違いによる挙動の差異が生じることもありません。

  2. したがって、microLib を使用しない場合、オリジナルの libc が導入され、C ソースライブラリ内の多くの相互作用関数が Semihosting コードを生成し、デバッグ時に動作がカクカクし、デバッグから外れると全く動作しなくなります。

  3. 要するに、microLib を使用しない場合、C 標準ライブラリ関数の使用には非常に注意が必要であり、システム相互作用関数が Semihosting コードを生成することを避けるべきです。

祖先の法則は変えられない#

私が業界に入った時から、私の上司は printf 系列の関数を使用することを厳しく禁止し、あるいはすべての libc 関数、mallocmemsetstrcpyなどを禁止しました。また、標準 C ライブラリはstdint.hstdlib.hstdbool.hのみを導入することになりました。その結果、膨大な数の独自実装の文字列操作、バッファ操作、トレースログなどが生まれました。malloc がスレッドのスタックオーバーフローを避けるために使えるとすれば、静的メモリはバグの規模を制御可能にしますが、他の実装はなぜ使えないのでしょうか?

要するに、祖先の法則は変えられず、今でもこのような状況です。

手がかり#

この人物のブートローダの脆弱性紹介を見ていると(実際にはスタック操作の問題でもあります)、以下の文章に出会いました。おそらくこの祖先の法則の出所を解明できるかもしれません。

Semihosting は本当に組み込みの盲腸なのか?- 腾讯云开发者社区 - 腾讯云 (tencent.com)

検証#

以下は一部のコードです。clock (); はシステム相互作用を生成する典型的なコードです。このプロジェクトでは microLib が無効化されています。

#include <stdio.h>
#include <time.h>

int main(void)
{
    // 一部の初期化コードを省略
    while (1)
  	{
        clock_t tTime = clock();
        HAL_GPIO_TogglePin(GPIOH, GPIO_PIN_5);
        HAL_Delay(500);
    }
}

デバッグモードで実行

まず、clock () 関数に関連する逆アセンブルを見て、0x0800037C アドレスにジャンプして clock () 関数を実行します。

   109: clock_t tTime = clock(); 
0x08002386 F7FDFFF9  BL.W          0x0800037C clock
0x0800238A 9001      STR           r0,[sp,#0x04]
0x0800238C F6414000  MOVW          r0,#0x1C00
0x08002390 F6C50002  MOVT          r0,#0x5802
0x08002394 2120      MOVS          r1,#0x20

clock () 関数が存在する場所で、確かに BKPT ソフトブレークポイントが現れました。

ここでBKPTCortex-MBreak Point(ソフトブレークポイント)命令であり、定数0xABSemihosting専用の暗号です。もし使用しているデバッグツールがたまたま Semihosting をサポートしている場合、ソフトウェアは停止せずに正常に動作します。しかし、電源を切って再起動すると、”BKPT 命令が非デバッグモードで実行されると、Cortex-M プロセッサは Hardfault に入ります”。

0x0800037C 2100      MOVS          r1,#0x00
0x0800037E 2010      MOVS          r0,#0x10
0x08000380 BEAB      BKPT          0xAB ;ここで停止します。これがSemihostingコードのソフトブレークポイントです
0x08000382 4905      LDR           r1,[pc,#20]  ; @0x08000398
0x08000384 6809      LDR           r1,[r1,#0x00]
0x08000386 1A40      SUBS          r0,r0,r1

最適化を開くことで回避できるか?#

実際、現代のコンパイラは非常に賢く、少しの最適化を行うことで、自分でも気づかなかった多くのバグを修正します。

O3 の状態でコンパイルしても、BKPT が発生するのは避けられません。この libc はバイナリ形式で書き込みファイルにリンクされるべきです。

どの関数を避けるべきか?#

参考文献には以下のように書かれています。

1. 標準入力 / 出力(Standard I/O)#

  • printf 系列関数:例えば printf、fprintf、sprintf など、標準出力デバイス(通常はホストのコンソール)にフォーマットされた出力を行います。
  • scanf 系列関数:例えば scanf、fscanf、sscanf など、標準入力デバイス(通常はホストのキーボード入力)からフォーマットされた入力を行います。

2. ファイル操作(File Operations)#

  • fopen:ファイルを開きます。
  • fclose:ファイルを閉じます。
  • fread:ファイルからデータを読み取ります。
  • fwrite:ファイルにデータを書き込みます。
  • fseek:ファイルポインタを指定位置に移動します。
  • ftell:ファイルポインタの現在位置を取得します。
  • fflush:ファイル出力バッファをフラッシュします。

3. 時間と日付(Time and Date)#

  • time:現在の時間を取得します。
  • clock:プロセッサの時間を取得します。
  • difftime:2 つの時間点の時間差を計算します。
  • strftime:時間と日付を文字列にフォーマットします。

4. エラー処理(Error Handling)#

  • perror:標準エラー出力デバイスにエラー情報を出力します。
  • strerror:エラーコードに対応するエラー情報文字列を返します。

5. システムコール(System Calls)#

  • exit:プログラムを終了し、ステータスコードを返します。
  • system:システムコマンドを実行します(組み込みシステムではあまり使用されませんが、ホスト上でデバッグする際には役立つことがあります)。

6. その他の補助機能(Other Auxiliary Functions)#

  • getenv:環境変数の値を取得します。
  • putenv:環境変数を設定します(あまり一般的ではありません)。
  • remove:ファイルを削除します。
  • rename:ファイルの名前を変更します。

元の記事は非常に面白いので、ぜひご覧ください#

明らかに私たちはその特徴 4 に該当し、さらに過激です。

【“組み込み盲腸炎” の潜伏と誘因】

五星上将マッカーサーはかつてコメントしました:ある度に病院に行くと、癌が始まる。あなたのような偽専門家がSemihostingをこんなに恐ろしいものだと言い、「コンパイラがデフォルトで埋め込まれている」と言うなら、私はどうして今まで元気に過ごせたのでしょうか?私はどうして一度も遭遇したことがないのでしょうか?

恕我直言、あなたは以下の特徴に該当するかもしれません:

  1. 大多数の場合、Arm Compiler 5を使用している;
  2. 大多数の場合、MicroLibをデフォルトで使用している;
  3. Arm Compiler 6MicroLibを選択しないときに「デバッグ状態ではすべて正常だが、プログラムをダウンロードして直接実行するとフリーズする」という現象に遭遇し、そのために小さなノートにMicroLibのみを使用することをメモしている;
  4. malloc以外のlibc関数を一切使用せず、printfさえも含まれている;
  5. 使用しているプログラムテンプレートは大物が作成したものである;
  6. アプリケーション開発はチップメーカーから提供された例のプロジェクトに基づいている;
  7. RT-Threadのような「ワンストップサービス」を提供するソフトウェアプラットフォームを使用している。

私が多くのことを挙げたように見えるかもしれませんが、実際には 2 つの状況に分けられます:

  1. 突然の幸運;
  2. 誰かがあなたのために重荷を背負っている。

この記事は Mix Space によって xLog に同期更新されました
元のリンクは https://www.yono233.cn/posts/shoot/24_8_13_Semihosting


読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。