質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.37%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

関数

関数(ファンクション・メソッド・サブルーチンとも呼ばれる)は、はプログラムのコードの一部であり、ある特定のタスクを処理するように設計されたものです。

VirtualBox

VirtualBoxは、現在米オラクル社が開発している、 x86仮想化ソフトウェア・パッケージの一つです。

Q&A

解決済

1回答

1397閲覧

C言語 自作ブートローダー 関数を新たに定義すると動かなくなる

kazuyakazuya

総合スコア193

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

関数

関数(ファンクション・メソッド・サブルーチンとも呼ばれる)は、はプログラムのコードの一部であり、ある特定のタスクを処理するように設計されたものです。

VirtualBox

VirtualBoxは、現在米オラクル社が開発している、 x86仮想化ソフトウェア・パッケージの一つです。

0グッド

0クリップ

投稿2020/11/05 07:06

エラーの原因がわからないのでお願いします

ブートローダーをアセンブリ言語で書き、それ以降はcで書きたいです。
リンクさせる方法がわからないので
あらかじめどこのアドレスから制御を渡すか決めておいて
そこにcのプログラムを配置して何とか動かしています。

これを参考にしました

gcc -c ファイル名.c objcopy -O binary -j .text ファイル名.o bin.file

これで生成されたrawバイナリファイルの先頭から制御を渡せばそのまま実行できるはず

#define Fontdata_Base 0x7C00 + 512 * 8 #define Vram_Base_Address 0xA0000 void loop(void); void DisplayMessage_Small(char*,int,int); void DisplayMessage_Small_Loop(char *,char *); void DidplayMessage_Small_Strings(char *,int,int,int); void main_kernel(void){ char message_loding[] = "loding plese wait"; DidplayMessage_Small_Strings(message_loding,17,28,400); loop(); } void loop(void){ for(;;){} } void DidplayMessage_Small_Strings(char *Asciicode_String_Address,int String_Count,int X,int Y){ int Count; int X_Count; for(Count = 0; Count < String_Count ; Count++){ char * Asciicode_Address = Asciicode_String_Address + Count; X_Count = X + Count; DisplayMessage_Small(Asciicode_Address,X_Count,Y); } } void DisplayMessage_Small(char *Asciicode_Address,int X,int Y){ char *Fontdata_Address = (Fontdata_Base + (0x200 * 26) + (*Asciicode_Address * 16)); //*Asciicode_Address char *Vram_Address = Vram_Base_Address; Vram_Address = Vram_Address + X + (Y * 80); DisplayMessage_Small_Loop(Fontdata_Address,Vram_Address); } void DisplayMessage_Small_Loop(char *Asciicode_Address,char * Vram_Address){ int count; for(count = 0; count< 16; count++){ char Asciicode = *(Asciicode_Address + count); char *Vram = Vram_Address + (80 * count); *Vram = Asciicode; } }

display~は画面上に文字を表示させる関数です。
そしてプログラムはmain_kernel関数から実行されていきます。
結果がこちらです。
youtube
"run next stage"コマンドを実行すると上記のcプログラムへ制御が移ります。
見た限りうまく動作しています。

#define Fontdata_Base 0x7C00 + 512 * 8 #define Vram_Base_Address 0xA0000 void loop(void); void DisplayMessage_Small(char*,int,int); void DisplayMessage_Small_Loop(char *,char *); void DidplayMessage_Small_Strings(char *,int,int,int); void DisplayMessage_Big(char*,int,int); void DisplayMessage_Big_Loop(char *,char *); void main_kernel(void){ char message_loding[] = "loding plese wait"; DidplayMessage_Small_Strings(message_loding,17,28,400); loop(); } void loop(void){ for(;;){} } void DisplayMessage_Big(char *Asciicode_Address,int X,int Y){ char *Fontdata_Address = (Fontdata_Base + ((*Asciicode_Address) - 0x41) * 512); //*Asciicode_Address char *Vram_Address = Vram_Base_Address; Vram_Address = Vram_Address + X + (Y * 80); DisplayMessage_Big_Loop(Fontdata_Address,Vram_Address); } void DisplayMessage_Big_Loop(char *Asciicode_Address,char * Vram_Address){ int Round1_Count = 0; //縦 int Round2_Count = 0; char *Vram; char Data; for(Round1_Count = 0; Round1_Count< 64; Round1_Count++){ Vram = Vram_Address + (Round1_Count * 80); for(Round2_Count = 0; Round2_Count< 8; Round2_Count++){ Data = *(Asciicode_Address + Round2_Count + (Round1_Count * 8)); *Vram = Data; Vram = Vram + 1; } } } void DidplayMessage_Small_Strings(char *Asciicode_String_Address,int String_Count,int X,int Y){ int Count; int X_Count; for(Count = 0; Count < String_Count ; Count++){ char * Asciicode_Address = Asciicode_String_Address + Count; X_Count = X + Count; DisplayMessage_Small(Asciicode_Address,X_Count,Y); } } void DisplayMessage_Small(char *Asciicode_Address,int X,int Y){ char *Fontdata_Address = (Fontdata_Base + (0x200 * 26) + (*Asciicode_Address * 16)); //*Asciicode_Address char *Vram_Address = Vram_Base_Address; Vram_Address = Vram_Address + X + (Y * 80); DisplayMessage_Small_Loop(Fontdata_Address,Vram_Address); } void DisplayMessage_Small_Loop(char *Asciicode_Address,char * Vram_Address){ int count; for(count = 0; count< 16; count++){ char Asciicode = *(Asciicode_Address + count); char *Vram = Vram_Address + (80 * count); *Vram = Asciicode; } }

DisplayMessage_Big、DisplayMessage_Big_Loop関数を追加で配置しました。
これは64×64のフォントを表示させる関数です。
main_kernel内で呼び出していないので実行されることはないです。
呼び出されないので結果はさっきのと変わらないはずと思いきや・・・
イメージ説明
ちなみにbig関数とsmall関数の定義する順番(上下)を入れ替えたところエラーは出なくなりました。
bigとsamllのプロトタイプ宣言の上下を入れ替えたところエラーは出なくなりましたが
何故か画面に"loding please wait"が表示されませんでした。

何が原因でこのようになるのでしょうか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

実行ファイルのデータ構造は、残念ながらあなたが思ってるような単純なものではないです。
オブジェクトファイルから、実行ファイルに変換するのはリンカ、ですが、リンカはパソコン上で実行するための実行アドレスをベースに機械語を配置していきます
パソコンのOSはその実行ファイルのフォーマット(exeファイル)から配置アドレスを検出し、それに合うように実行イメージをメモリ上に配置し、決められたエントリアドレスから実行させます

あなたがしようとすることを実現するためには、
・配置アドレスを決め打ちで指定して
・エントリアドレスもまた決め打ちで指定
する必要があります

ここで全部説明するのはムリなので、とりあえず、
「GCC セクション」でぐぐって一通り読んでみてください。

投稿2020/11/05 07:39

y_waiwai

総合スコア88024

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kazuyakazuya

2020/11/05 07:52 編集

実行ファイル=実行可能ファイルのことなら 実行ファイルにはこのデータを仮想メモリのどこから展開するか~などOSが解釈するための余計な情報が含まれているので・・・ objcopyを使って コード本体を取り出しています。(のつもり)
y_waiwai

2020/11/05 07:56

その取り出しているコード本体はどこのアドレスで実行するようなものなんでしょう。 よく考えてみましょうよ。 あなたが決めたアドレスに勝手に持ってきても、呼び出す関数が、そのアドレスに存在してなければ暴走しますよ。 #まさにあなたが直面してる問題ですがな
kazuyakazuya

2020/11/05 07:59

つまり、・配置アドレスを決め打ちで指定 した上で生成したオブジェクトファイルに対して objcopyを使う必要があるってことですか?
y_waiwai

2020/11/05 08:44

まあ、そゆことですな。 関数を使わないコードなら、アドレスの依存性はないので動くかもしれませんが。
kazuyakazuya

2020/11/07 15:30

リンカスクリプトで必要最低限のセクションの配置アドレスを指定し 実行ファイル(exe)を生成。 objcopyで実行ファイルのセクションを切り取って適切なアドレスマップさせるといった感じでいけますか? また、相対アドレスでアクセスするようにできれば どこのアドレスからマップしても動くと思うので(?)セクションを指定する必要はないのでしょうか?
y_waiwai

2020/11/08 02:13

まあ、リンカスクリプトを駆使できるようになれば、特定の関数を独立したセクションとして、アドレスを決め打ちするってこともできますね > また、相対アドレスでアクセスするようにできれば そうできる、はずです。 GCCには相対アドレスにするオプションもあるけど、X86で完全にそうできるかどうかは確認してません。アセンブルコードを出すようにして確認する必要がありますな
kazuyakazuya

2020/11/08 03:09

-fPIEオプションをつけてrawバイナリを生成したら問題なく実行できました! もし、この方法が使えなくなったらリンカスクリプトにチャレンジします 有難うございました
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.37%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問