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

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

新規登録して質問してみよう
ただいま回答率
85.35%
アセンブリ言語

アセンブリ言語とは、機械語を人間にわかりやすい形で記述した低水準言語です。

C

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

ファイル

ファイルとは、文字列に基づいた名前又はパスからアクセスすることができる、任意の情報のブロック又は情報を格納するためのリソースです。

GCC

GCCはGNU Compiler Collectionの略です。LinuxのC言語コンパイラのデファクトスタンダードであり、数多くの他言語やプラットフォームサポートもします。

Q&A

1回答

2493閲覧

gcc nasm書式のアセンブリコードを吐かせたい

kazuyakazuya

総合スコア193

アセンブリ言語

アセンブリ言語とは、機械語を人間にわかりやすい形で記述した低水準言語です。

C

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

ファイル

ファイルとは、文字列に基づいた名前又はパスからアクセスすることができる、任意の情報のブロック又は情報を格納するためのリソースです。

GCC

GCCはGNU Compiler Collectionの略です。LinuxのC言語コンパイラのデファクトスタンダードであり、数多くの他言語やプラットフォームサポートもします。

0グッド

0クリップ

投稿2020/03/05 06:30

編集2020/03/06 01:11

カーネルすべてをアセンブリ言語で作成するのは嫌なのでC言語ファイルとアセンブリ言語ファイルを
くっつけたい。
C言語コード→GCC
アセンブリ言語コード→NASM
C言語コードをGCCでアセンブルしてアセンブリに変換して
もともとのアセンブリ言語ファイルと合併させる方法を思いついたが
書式が違うのでそれはできない・・・と思っていたができる方法があるらしいです。

リンク内容

;オブジェクトファイルを生成します。 gcc -fno-asynchronous-unwind-tables -s -c struct_offsetof.c -o s3.obj
;objconvでnasm形式のアセンブリファイルに変換する objconv -fnasm s3.obj

さっそくobjconvをインストールして試してみました。
objconvはこちらで簡単に手に入れられた。

C言語コード

c

1int aaa (void){ 2 int i,j; 3 for(i=1;i<21;i++) 4 j= i + 100; 5 return 0; 6 } 7

上記2つのコマンドを実行しました。
以下、NASM形式に変換されたであろう(たぶん)アセンブリコード

s

1; Disassembly of file: sample.obj 2; Thu Mar 5 15:20:20 2020 3; Mode: 32 bits 4; Syntax: YASM/NASM 5; Instruction set: 80386 6 7 8global _aaa: function 9 10 11SECTION .text align=4 execute ; section number 1, code 12 13.text: ; Local function 14 15_aaa: 16 push ebp ; 0000 _ 55 17 mov ebp, esp ; 0001 _ 89. E5 18 sub esp, 16 ; 0003 _ 83. EC, 10 19 mov dword [ebp-4H], 1 ; 0006 _ C7. 45, FC, 00000001 20 jmp ?_002 ; 000D _ EB, 0D 21 22?_001: mov eax, dword [ebp-4H] ; 000F _ 8B. 45, FC 23 add eax, 100 ; 0012 _ 83. C0, 64 24 mov dword [ebp-8H], eax ; 0015 _ 89. 45, F8 25 add dword [ebp-4H], 1 ; 0018 _ 83. 45, FC, 01 26?_002: cmp dword [ebp-4H], 20 ; 001C _ 83. 7D, FC, 14 27 jle ?_001 ; 0020 _ 7E, ED 28 mov eax, 0 ; 0022 _ B8, 00000000 29 leave ; 0027 _ C9 30 ret ; 0028 _ C3 31 32 nop ; 0029 _ 90 33 nop ; 002A _ 90 34 nop ; 002B _ 90 35 36 37SECTION .data align=4 noexecute ; section number 2, data 38 39 40SECTION .bss align=4 noexecute ; section number 3, bss 41 42 43SECTION .rdata$zzz align=4 noexecute ; section number 4, const 44 45 db 47H, 43H, 43H, 3AH, 20H, 28H, 4DH, 69H ; 0000 _ GCC: (Mi 46 db 6EH, 47H, 57H, 2EH, 6FH, 72H, 67H, 20H ; 0008 _ nGW.org 47 db 47H, 43H, 43H, 2DH, 38H, 2EH, 32H, 2EH ; 0010 _ GCC-8.2. 48 db 30H, 2DH, 33H, 29H, 20H, 38H, 2EH, 32H ; 0018 _ 0-3) 8.2 49 db 2EH, 30H, 00H, 00H ; 0020 _ .0.. 50 51 52

この元C言語コードをアセンブリ言語本体のプログラム(カーネル)に
%include "../16_protect_mode/sample.asm"
これでのっけて、正常にコンパイルできるかやってみたところ

../16_protect_mode/sample.asm:11: warning: ignoring unknown section attribute: "execute" [-w+other] ../16_protect_mode/sample.asm:37: warning: ignoring unknown section attribute: "noexecute" [-w+other] ../16_protect_mode/sample.asm:40: warning: ignoring unknown section attribute: "noexecute" [-w+other] ../16_protect_mode/sample.asm:43: warning: ignoring unknown section attribute: "noexecute" [-w+other] ../16_protect_mode/sample.asm:11: warning: ignoring unknown section attribute: "execute" [-w+other] ../16_protect_mode/sample.asm:37: warning: ignoring unknown section attribute: "noexecute" [-w+other] ../16_protect_mode/sample.asm:40: warning: ignoring unknown section attribute: "noexecute" [-w+other] ../16_protect_mode/sample.asm:43: warning: ignoring unknown section attribute: "noexecute" [-w+other] ../16_protect_mode/sample.asm:11: warning: ignoring unknown section attribute: "execute" [-w+other] ../16_protect_mode/sample.asm:37: warning: ignoring unknown section attribute: "noexecute" [-w+other] ../16_protect_mode/sample.asm:40: warning: ignoring unknown section attribute: "noexecute" [-w+other] ../16_protect_mode/sample.asm:43: warning: ignoring unknown section attribute: "noexecute" [-w+other] ../16_protect_mode/sample.asm:11: warning: ignoring unknown section attribute: "execute" [-w+other] ../16_protect_mode/sample.asm:15: error: binary format does not support any special symbol types ../16_protect_mode/sample.asm:37: warning: ignoring unknown section attribute: "noexecute" [-w+other] ../16_protect_mode/sample.asm:40: warning: ignoring unknown section attribute: "noexecute" [-w+other] ../16_protect_mode/sample.asm:43: warning: ignoring unknown section attribute: "noexecute" [-w+other]

生成されたアセンブリコードのうち

s

1_aaa: 2 push ebp ; 0000 _ 55 3 mov ebp, esp ; 0001 _ 89. E5 4 sub esp, 16 ; 0003 _ 83. EC, 10 5 mov dword [ebp-4H], 1 ; 0006 _ C7. 45, FC, 00000001 6 jmp ?_002 ; 000D _ EB, 0D 7 8?_001: mov eax, dword [ebp-4H] ; 000F _ 8B. 45, FC 9 add eax, 100 ; 0012 _ 83. C0, 64 10 mov dword [ebp-8H], eax ; 0015 _ 89. 45, F8 11 add dword [ebp-4H], 1 ; 0018 _ 83. 45, FC, 01 12?_002: cmp dword [ebp-4H], 20 ; 001C _ 83. 7D, FC, 14 13 jle ?_001 ; 0020 _ 7E, ED 14 mov eax, 0 ; 0022 _ B8, 00000000 15 leave ; 0027 _ C9 16 ret ; 0028 _ C3 17 18 nop ; 0029 _ 90 19 nop ; 002A _ 90 20 nop ; 002B _ 90 21

これ以外は邪魔な情報が入っているのではないか?と考え上記以外は消して再度コンパイルしたところ
エラーなくしてコンパイルできました。
(実際にカーネル内でcall aaaをしてもエラーはでなかった。)

それで質問なのですが
上記のやり方でプログラムは正しく動くのでしょうか?
たまたまうまくいっているように見えるだけでしょうか?

不明点1 インラインアセンブラが反映されていない?

リンク内容

LinuxカーネルのIDT登録関数を持ってきました。

s

1#define _set_gate(gate_addr,type,dpl,addr,seg) \ 2do { \ 3 int __d0, __d1; \ 4 __asm__ __volatile__ ("movw %%dx,%%ax\n\t" \ 5 "movw %4,%%dx\n\t" \ 6 "movl %%eax,%0\n\t" \ 7 "movl %%edx,%1" \ 8 :"=m" (*((long *) (gate_addr))), \ 9 "=m" (*(1+(long *) (gate_addr))), "=&a" (__d0), "=&d" (__d1) \ 10 :"i" ((short) (0x8000+(dpl<<13)+(type<<8))), \ 11 "3" ((char *) (addr)),"2" ((seg) << 16)); \ 12} while (0) 13 14 15/* 16 * This needs to use 'idt_table' rather than 'idt', and 17 * thus use the _nonmapped_ version of the IDT, as the 18 * Pentium F0 0F bugfix can have resulted in the mapped 19 * IDT being write-protected. 20 */ 21void set_intr_gate(unsigned int n, void *addr) 22{ 23 _set_gate(0,14,0,0,0); 24/* 注意 値は適当です*/ 25}

s

1_set_intr_gate:; Function begin 2 push ebp ; 0025 _ 55 3 mov ebp, esp ; 0026 _ 89. E5 4 push ebx ; 0028 _ 53 5 sub esp, 16 ; 0029 _ 83. EC, 10 6 mov ecx, 0 ; 002C _ B9, 00000000 7 mov ebx, 4 ; 0031 _ BB, 00000004 8 mov edx, 0 ; 0036 _ BA, 00000000 9 mov eax, 0 ; 003B _ B8, 00000000 10 mov ax, dx ; 0040 _ 66: 89. D0 11; Note: Length-changing prefix causes delay on Intel processors 12 mov dx, 36352 ; 0043 _ 66: BA, 8E00 13 mov dword [ecx], eax ; 0047 _ 89. 01 14 mov dword [ebx], edx ; 0049 _ 89. 13 15 mov dword [ebp-8H], eax ; 004B _ 89. 45, F8 16 mov dword [ebp-0CH], edx ; 004E _ 89. 55, F4 17 nop ; 0051 _ 90 18 add esp, 16 ; 0052 _ 83. C4, 10 19 pop ebx ; 0055 _ 5B 20 pop ebp ; 0056 _ 5D 21 ret ; 0057 _ C3 22; _set_intr_gate End of function 23

中身で_set_gate関数を呼び出していないばかりか
_set_gate関数自体ない気がするのですが・・・

_set_gateを定義しないまま上記からコンパイルしようとしたところ

cmd

1../16_protect_mode/sample.asm:13: error: symbol `__set_gate' undefined 2../16_protect_mode/sample.asm:19: error: label `_set_system_intr_gate' changed during code generation [-w+error=label-redef-late] 3../16_protect_mode/sample.asm:28: error: symbol `__set_gate' undefined

と出たのでどこかしらに_set_gateがあるはずなのだが・・・

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

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

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

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

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

yohhoy

2020/03/05 08:02

リンク先の「Using a slightly modified version of your sed call, tweak the contents:」以降のステップも必要ではないですか?
kazuyakazuya

2020/03/05 08:07

オブジェクトファイルをリンクしてファイルを繋げたいというのなら 以降のステップも必要だが 私が今やっているのはリンクではなく 本当にそのまま生成したアセンブリプログラムを繋げてコンパイルしているだけだから それ以降のステップは必要ない と判断しました。 (必要でしたか?)
yohhoy

2020/03/05 08:22 編集

警告「ignoring unknown section attribute:~」が多発しているので、実効上は無視されているようにも見えますね。 残るエラー「binary format does not support any special symbol types」は気になりますが。
kazuyakazuya

2020/03/05 20:36

いらない部分(?)を消してアセンブルしたときは全くエラーは出ませんでした。
dodox86

2020/03/06 00:08 編集

質問者さんの環境でコンパイル~アセンブル~リンクが通るようになっても、どのような実行形式のファイルになるか回答者には分からないのですから、(<自作のカーネルを作られているようだから、OSからロードされるヘッダー付きのELF形式の実行ファイルなどではないのでしょう)「このやり方で正しく動くかどうか」と言う質問は検討と回答責任の範囲が広く、とても回答者には判断付かないことなのでは? と思います。そもそもやり方が特異なのですから、生成されたmapファイルや出力されたアセンブリ言語lstファイルを突き合わせて判断するしか無いのではないでしょうか。当面、質問者のkazuyakazuyaさんのカーネルの実行コードと同じセクションに属する限り動くかんじはしますが、切り貼りしたコードの断片が別のセクションに属してしまったり、変換済みコードの小さい断片のせいで動かなくなることも容易に想像できます。
dodox86

2020/03/06 00:12

回答の落としどころが分からず、(失礼ながら)これまでのご質問のように質問~回答~新たな小さい質問の追加~回答が長く続いてしまう懸念があります。(既に始まっている気がしますが)
kazuyakazuya

2020/03/06 01:06 編集

>ヘッダー付きのELF形式の実行ファイルなどではないのでしょう boot.img ディスクイメージなので ELF形式とかの形式うんぬんではなく ただのバイト列だと思うのですが・・・ (nasmは余計な情報・ヘッダーを加えることなくコードをそのままコンパイルするはず たぶん) >実行コードと同じセクションに属する限り動くかんじはしますが ここで言うセクションとはなんですか? カーネルをC言語で作る場合セクションを指定する必要があるみたいですが それってオブジェクトファイルをリンカでくっつける場合ですよね。 今回は生成されたアセンブリコードをリンカを使わず本当にそのままくっつけているだけなので セクションうんぬんは必要ないと思うのですが 必要でしたか?
dodox86

2020/03/06 01:25 編集

> boot.img ディスクイメージなので ELF形式とかの形式うんぬんではなくただのバイト列だと思うのですが・・・ リロケータブルではない、アドレスが確定済みのフラットなイメージを扱われているのでいるのであればその通りだと思います。 質問文中に「boot.img ディスクイメージ」との言葉が出てきたのは本質問中では今が初めてなので、私は(想像しつつも確実ではなかったので)分かりませんでした。 > 今回は生成されたアセンブリコードをリンカを使わず本当にそのままくっつけているだけなのでセクションうんぬんは必要ないと思うのですが ちょっと詳細なビルド状況は分かりませんが、一般的には分割されたアセンブリコード~オブジェクトコードをまとめあげるのはリンカーのはずです。リンカースクリプトに応じてアドレスが確定しますが、その後、GNUであればbinutilなどのサポートツールでファイルから不要な情報を除去する流れだと思います。定数データも実行プログラムと同じセグメントに配置されているのであれば、複数のセクションの意識も無く、ひとつのセクション(セクションと言う概念もリンクが終わって以降はほとんど存在しませんが)で取り扱えるはずですし、実行時に各セグメントを自力で整備されているのであれば問題ないです。必要ない確信があればそれで良いと思います。(実際、今は動いているのでしょうし)
kazuyakazuya

2020/03/06 01:37

>ちょっと詳細なビルド状況は分かりませんが 本来、 ①ブートローダーからカーネルの最初くらいまで書いたアセンブリコード →NASM ②C言語で書かれたカーネルプログラム →GCC ①、②それぞれオブジェクトコードを生成し gcc オブジェクトファイル1,オブジェクトファイル2 のようにしてgccをリンカとして使い コードをくっつける予定でしたが なんだかんだでできませんでした。 そこで、C言語のコード②をNASMで認識できるアセンブリコードに変換してから ①と本当にそのまま繋げてしまい nasmで実行可能コードへ変換している という感じです。 (今考えてみればこの方法だとアセンブリコード側で定義したマクロを C言語側で使えない たぶん) 実際にちゃんと動いているのかという話ですが かなりあやしいです。 LinuxのIDT登録関数の引数(IDTの場所・処理ルーチンの場所の2点だけ) を変更し実際に走らせ、 ソフトウエア割り込みで呼び出したのですが(INT 0x00) エラーになるため正常に登録できていないのだと思います。
dodox86

2020/03/06 02:15 編集

> エラーになるため正常に登録できていないのだと思います。 そういうことだとしますと、やはり正しく動かない原因は色々と考えられて、nasmやinlineアセンブラをかましたことだけが原因とは限らないと思うのです。流用したIDT登録関数を2回呼んでいるにあたって、前後で何か準備や前提条件が必要であって当然のように思いますし、それはnasmとは関係ない部分かもしれません。あるいは両方かもしれません。つまり、質問者のkazuyakazuyaさんにとって全体として「正しく動くか」と言う質問への回答には至りません。それが先の私のコメント「回答責任の範囲が広く」にあたります。もちろん私が分からないだけで、他の回答者さんには分かることかもしれません。ですので、以降はコメントを控えます。長々とすみません。
kazuyakazuya

2020/03/06 10:56 編集

質問の内容が変わってしまい申し訳ないのですが (長引きそうなら新たに質問を立てます。) 上記で書いた通り アセンブリプログラム、C言語プログラムをそれぞれオブジェクトファイルにし gccをリンカとして使いくっつけたいです。 ①アセンブリプログラム(ブートローダーとか) これをnasmでオブジェクトファイルへ ②Cプログラム(カーネル) これをgccでオブジェクトファイルへ ②は gcc -o -c sample.o sample.cで正常に(たぶん)オブジェクトファイルへ変換できました。 で、問題なのが① 例)nasm -o -f elf boot.o boot.s ディスクイメージはただのバイト列なのでオプションでelfを選んではいけない (elfファイルからテキスト領域だけを取り出すという手も思いついたが そもそも疑似命令のところでコンパイルに失敗するのでこれは不可能) こういう場合nasmでどうやってオブジェクトファイルを生成すればいいのでしょうか? nasm -hf で -f で選べるオプションを見てみたのですがそれらしいものはありませんでした。
kazuyakazuya

2020/03/06 10:49

例えば・・・ http://aikiriao.hatenablog.com/entry/2017/11/04/025501 BITS 16 ; 16ビット(リアル)モード ORG 0x7c00 ; このプログラムの読み込み位置 JMP entry ; goto entry; DB 0x90 ; →nasm -f elf boot2.s -o boot2.o まったく同じコード・コマンドを使用しましたが boot2.s:2: error: parser: instruction expected 疑似命令のところで必ず詰まります。。。
kazuyakazuya

2020/03/06 11:19

やっぱなんでもないです すみません
guest

回答1

0

_set_gate関数自体ない気がするのですが・・・

が質問でいいんですかね?
_set_gateは、関数ではなくてマクロなので、
無くて当たり前なのですが。

投稿2020/03/05 20:42

PingHermit

総合スコア478

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

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

kazuyakazuya

2020/03/05 20:52 編集

回答ありがとうございます。 すみません。そうですね set_intr_gateの中に組み込まれていますね。(たぶん) マクロ関数の_set_gateを定義してアセンブリしたパターンと _set_gateを定義しないでアセンブルしたパターンのコードを見比べていて気付きましたが mov dx, 36352 ; 0043 _ 66: BA, 8E00 mov dword [ecx], eax ; 0047 _ 89. 01 mov dword [ebx], edx ; 0049 _ 89. 13 mov dword [ebp-8H], eax ; 004B _ 89. 45, F8 mov dword [ebp-0CH], edx ; 004E _ 89. 55, F4 ここかな(?)
PingHermit

2020/03/05 22:29

アセンブラはよく知らないが、 mov ax, dx あたりも入っている気がしますが。 ついでに、前のエラーリスト、 .text がエラーでは? インテル形式は text などと、'.' がない形式では? まあ、アセンブラはよく知らないが。 前と後で、質問が違うみたいなので、 質問は分けた方がいいと思いますよ。
PingHermit

2020/03/05 22:42

あ、前準備も含めたら mov ecx, 0 からかも。
PingHermit

2020/03/05 23:13

ついでに、gcc のコンパイルオプション、最適化効かせてないでしょ。
kazuyakazuya

2020/03/06 01:10

最適化を効かせなくてはいけないのでしょうか?
kazuyakazuya

2020/03/06 01:11

>前と後で、質問が違うみたいなので、 質問は分けた方がいいと思いますよ。 すみません。タイトルを変更しました
PingHermit

2020/03/06 03:45

別に、最適化しなければいけないわけじゃないですが、 少々冗長に思えたので(^^; まあ、どっちでもいいことではあります。 インラインアセンブラ部分は、volatile なので最適化から外されますし。 最適化される部分は、その前後だけにしか適用されませんから。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問