C言語で書かれたプログラムの中に、アセンブラで書かれた関数を使うため、インラインアセンブラで関数を作っていたのですが、私の能力の限界を感じたので、是非、ご教授願います。以下に示します。
元のアセンブラの関数write_mem82(int addr, int data)
MOV EAX, [ESP+4]
MOV AL, [ESP+8]
MOV [EAX], AL
RET
です。これは、OS○作○門という本に載っていたものですが、プログラムをインラインアセンブラにすると、成功するのかふと疑問に思ったのです。よって、アセンブラの種類は、nasmを基にしたnaskです。
こういうことは、その本のサポートページか何かで質問すればよい的なことをおっしゃる方もおられると思います。残念ながら、サポートページは、ほぼ凍結状態で、何年待てば回答が返ってくるのか?という状態です。
そういう経歴で、ここの質問させていただくに至りました。
肝心の、私が書いてコンパイルエラーになるプログラムを書きます。
static __inline__ void write_mem82(int addr, int data){
__asm__ (
"MOV EAX,[ESP+4]":
"MOV AL,[ESP+8]"
"MOV [EAX],AL"
"RET"
);
}
です。"MOV [EAX],AL"でエラーが出ます内容は構文が間違っているという内容のものです。なお、関数の名前は、意図的に変えてあります。オリジナルとは違います。
大した関数ではないのかもしれないのですが、わからないのでよろしくおねがいいたします。
No.7ベストアンサー
- 回答日時:
gcc/gasの流儀に従って書くならこうじゃないでしょうか。
void write_mem82(int addr, int data) {
char data8 = (char)data;
__asm__(
"movb%1, (%0)\n\t"
: : "r"(addr), "r"(data8)
);
}
「GCC インラインアセンブラ」でググれば情報は見つかります。
この回答への補足
回答くださりありがとうございます。結果から申しますと。無事動きました。!!エラーもありません。というか、私もこんなコードをかけるように勉強したいです。検索のキーワードをあげてくださっていますが、私が気付いていない可能性が高いので、お勧めのサイトがあれば、(書籍でもいいです。)紹介していただきたいのですが、お願いできますでしょうか。(大げさかもしれませんが、本心では弟子にしてほしいぐらいです。感動しました。でもさっぱり分かっていないように思います。)実際にコンパイルしたソースと実行結果のログを載せておきます。ありがとうございました。
bootpack.c --------------------------
static __inline__ void io_hlt2(void){
__asm __volatile (
"HLT\n\t"
"RET"
);
}
void write_mem82(int addr, int data) {
char data8 = (char)data;
__asm__(
"movb%1, (%0)\n\t"
: : "r"(addr), "r"(data8)
);
}
void HariMain(void)
{
int i;
for (i = 0xa0000; i <= 0xaffff; i++) {
write_mem82(i, i & 0x0f);
}
for (;;) {
io_hlt2();
}
}
結果のログーーーーーーーーーーーーーーーーーーーーーーーー
C:\TEST\test>make run
C:\TEST\test>..\z_tools\make.exe run
../z_tools/make.exe -r img
make.exe[1]: Entering directory `C:/TEST/test'
../z_tools/make.exe -r haribote.img
make.exe[2]: Entering directory `C:/TEST/test'
make.exe[2]: `haribote.img' is up to date.
make.exe[2]: Leaving directory `C:/TEST/test'
make.exe[1]: Leaving directory `C:/TEST/test'
copy haribote.img ..\z_tools\qemu\fdimage0.bin
1 個のファイルをコピーしました。
../z_tools/make.exe -r -C ../z_tools/qemu
make.exe[1]: Entering directory `C:/TEST/z_tools/qemu'
qemu.exe -L . -m 32 -localtime -std-vga -fda fdimage0.bin
make.exe[1]: Leaving directory `C:/TEST/z_tools/qemu'
C:\TEST\test>
ここまでーーーーーーーーーーーーー
回答いただくまで作っていたプログラムがあるのですが、エラーが1つだけありHLTをスキップしてしまうものでした。ついでに載せておきます。
bootpack.c------------------------ここから
asm("io_hlt2:");
asm("haltl");
asm("ret");
extern void io_hlt2(void);
asm("write_mem82:");
asm("movl %ecx, [%esp+4]");
asm("movl %al, [%esp+8]");
asm("movl [%ecx], %al");
asm("ret");
extern void write_mem82(int addr, int data);
void HariMain(void)
{
int i;
for (i = 0xa0000; i <= 0xaffff; i++) {
write_mem82(i, i & 0x0f);
}
for (;;) {
io_hlt2();
}
}
ここまでーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
よろしくおねがいいたします。
No.13
- 回答日時:
なぜインラインアセンブラ中にretを書いたらいけないかですがサンプルのソースを見た方がわかりやすいかと思います。
FreeBSDのgccでのコンパイルなので本当に参考程度ですが。
% cat halt.c
void
io_hlt2(void)
{
__asm__ __volatile__(
"hlt\n\t"
"ret"
);
}
% cc -m32 -O2 -S halt.c
% cat halt.s
.file "halt.c"
.text
.p2align 4,,15
.globl io_hlt2
.type io_hlt2, @function
io_hlt2:
pushl %ebp
movl %esp, %ebp
#APP
hlt
ret
#NO_APP
popl %ebp
ret
.size io_hlt2, .-io_hlt2
.ident "GCC: (GNU) 4.2.1 20070831 patched [FreeBSD]"
.section .note.GNU-stack,"",@progbits
%
ラベルのio_hlt2:からpopl %ebpの次のretまでがio_hlt2関数で、#APP~#NO_APPの間がインラインアセンブラの出力です。
上記の例だとpopl %ebpしてからretすべきなのに、インラインアセンブラ中でそれをせずにretしてしまってます。
またコンパイラが用意しているretも無視することになります。
popl %ebpに関してはコンパイルオプションによりする必要のないケースもありますが、それを期待したコードにすべきでもありません。
No.12
- 回答日時:
#7の補足で解決はしてる?んですね。
>static __inline__ void io_hlt2(void){
>__asm __volatile (
>"HLT\n\t"
>"RET"
>
>);
>
>}
はHLTがスキップされずに
>static __inline__ void io_hlt2(void){
>__asm__ (
>"HLT"
>);
>
>}
はHLTがスキップされるというのはわかりませんが。
__asm__ __volatile__("HLT");
の方がいいですけど、HLTがスキップされるのとは関係ないでしょうし・・・
retは書いてはいけないのは確かなんだけどなぁ・・・(コンパイルできても実行としてはおかしいはず)
No.10
- 回答日時:
>でも教えてくださったコードで、なぜかエラーが出ます。
インラインアセンブラを使わない場合のものも、載せておきます。エラーメッセージちゃんと読んでますか?
「エラーを訳したりせずに、そのまま書きましょう。」とは書きましたが、あなた自身が読む必要はないなどとはいってませんけど。
どう見ても
>./z_tools/gas2nask.exe -a bootpack.gas bootpack.nas
>skip:HLT
スキップされてるのはio_hlt2()のHLTです(私はwrite_mem82()のコードしか書いてない)
>static __inline__ void io_hlt2(void){
>__asm__ (
>"HLT"
>);
>
>}
もしかしてですが、gas2nask.exeがhltには対応してないんじゃないでしょうか。
またはhltではなく別の表記とか。
>個人的にはインラインアセンブラを使わない方法に、興味があるのですが、一体どんな勉強をすればよいの>か、教えていただけるとありがたいです。
ふつうにC言語の勉強をすればよいだけかと。
>回答くださりありがとうございます。正直なところ、耳が痛いです。苦言ごもっともだと思います。しかし、恵まれた環境におられる方ならば、わざわざここまで質問をしないと思います。すぐ近くに
(以下略)
ご自分が恵まれた環境にないとおっしゃられてるようですけど、とっても恵まれてる方だと思いますよ。
インターネットで検索して調べるなんてことができるわけですから。
近くに聞く人がいないとかは些細なこと。
No.9
- 回答日時:
>よろしくおねがいいたします。
私もがんばります。「も」じゃないです。
一番がんばらないといけないのは、あなたです。
回答者ががんばってくれるかどうかは回答者次第。
この回答への補足
回答くださりありがとうございます。正直なところ、耳が痛いです。苦言ごもっともだと思います。しかし、恵まれた環境におられる方ならば、わざわざここまで質問をしないと思います。すぐ近くにいる誰かに聞けばよいわけですから。でも、そうじゃない人間もこうしてここにいるわけですから、私の表現が悪かったのだと思いますが、がんばる材料を、皆さま方いただいているという意味で、感謝いたします。
補足日時:2012/09/04 23:22No.8
- 回答日時:
#7の方が既に書いていらっしゃいますが、ログ中の
>../z_tools/gas2nask.exe -a bootpack.gas bootpack.nas
は、gas形式のアセンブラソースからnasm形式のアセンブラソースへコンバートしてるようなので
gccのインラインアセンブラで書くのはgas形式だと思います。
で、書くならたぶん
static __inline__ void write_mem82(int addr, int data){
__asm__("movb %1,%0": "=m"(*(char *)addr): "r"((char)data): "memory");
}
だと思います。
で、実はこれインラインアセンブラ使う必要がなくて
static __inline__ void write_mem82(int addr, int data){
*(char *)addr = (char)data;
}
で済むはずです。
#1でも既に書いてることもありますが
・[ESP+4]がaddr,[ESP+8]がdataのようなスタックレジスタ相対などの決めうちは×
・インラインアセンブラでretを書くのは× (例えば例で書かれているmain関数でwrite_mem82()がインライン展開されたらいっしょにretも展開されます)
・インラインアセンブラ内では好き勝手にレジスタは使用できず使えるものは決まってます(この辺はCコンパイラのマニュアルなど読んでください)
・C言語は高級アセンブラともいわれるくらいなのでアセンブラでできるほとんどの事はC言語でもインラインアセンブラを使わずに書けます。インラインアセンブラはC言語で書けないような事を書くときだけにしておいた方がいいです。
・C言語がどのようなコードを出力するのか想像できないのであればインラインアセンブラは使わない方がいいです。最適化のつもりがコンパイラのする最適化の足をひっぱったりします。
この回答への補足
回答くださりありがとうございます。解説がわかりやすくて助かります。でも教えてくださったコードで、なぜかエラーが出ます。インラインアセンブラを使わない場合のものも、載せておきます。せっかくいろんなことを教えてくださったのに、もったいないです。ありがとうございました。個人的にはインラインアセンブラを使わない方法に、興味があるのですが、一体どんな勉強をすればよいのか、教えていただけるとありがたいです。
bootpac.c アセンブラありーーーーーーーーーーーーーーーーーー
static __inline__ void io_hlt2(void){
__asm__ (
"HLT"
);
}
static __inline__ void write_mem82(int addr, int data){
__asm__("movb %1,%0": "=m"(*(char *)addr): "r"((char)data): "memory");
}
void HariMain(void)
{
int i;
for (i = 0xa0000; i <= 0xaffff; i++) {
write_mem82(i, i & 0x0f);
}
for (;;) {
io_hlt2();
}
}
エラーログーーーーーーーーーーーーーーーーーーーーーーーーーーーー
C:\TEST\test>make run
C:\TEST\test>..\z_tools\make.exe run
../z_tools/make.exe -r img
make.exe[1]: Entering directory `C:/TEST/test'
../z_tools/make.exe -r haribote.img
make.exe[2]: Entering directory `C:/TEST/test'
../z_tools/cc1.exe -I../z_tools/haribote/ -Os -Wall -quiet -o bootpack.gas bootp
ack.c
../z_tools/gas2nask.exe -a bootpack.gas bootpack.nas
skip:HLT
make.exe[2]: *** [bootpack.nas] Error 1
make.exe[2]: Leaving directory `C:/TEST/test'
make.exe[1]: *** [img] Error 2
make.exe[1]: Leaving directory `C:/TEST/test'
..\z_tools\make.exe: *** [run] Error 2
C:\TEST\test>
ここまでーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
bootbac.cアセンブラなしーーーーーーーーーーーーーーーーーーーーーーー
static __inline__ void io_hlt2(void){
__asm__ (
"HLT"
);
}
static __inline__ void write_mem82(int addr, int data){
*(char *)addr = (char)data;
}
void HariMain(void)
{
int i;
for (i = 0xa0000; i <= 0xaffff; i++) {
write_mem82(i, i & 0x0f);
}
for (;;) {
io_hlt2();
}
}
エラーログーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
C:\TEST\test>make run
C:\TEST\test>..\z_tools\make.exe run
../z_tools/make.exe -r img
make.exe[1]: Entering directory `C:/TEST/test'
../z_tools/make.exe -r haribote.img
make.exe[2]: Entering directory `C:/TEST/test'
../z_tools/cc1.exe -I../z_tools/haribote/ -Os -Wall -quiet -o bootpack.gas bootp
ack.c
../z_tools/gas2nask.exe -a bootpack.gas bootpack.nas
skip:HLT
make.exe[2]: *** [bootpack.nas] Error 1
make.exe[2]: Leaving directory `C:/TEST/test'
make.exe[1]: *** [img] Error 2
make.exe[1]: Leaving directory `C:/TEST/test'
..\z_tools\make.exe: *** [run] Error 2
C:\TEST\test>
ここまでーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
No.6
- 回答日時:
"MOV EAX,[ESP+4]\n\t"
"MOV AL,[ESP+8]\n\t"
"MOV [EAX],AL\n\t"
"RET"
だとどうですか?
前回の回答に書いた通り、検索で出てきた例の記述方法をまねているだけなので、うまくいくかはわかりません。
#ちなみに、「的を得ている」ではなく「的を射ている」です。
この回答への補足
回答くださりありがとうございます。
さっそく、試してみたところ。次のようになりました。
C:\TEST\test>make run
C:\TEST\test>..\z_tools\make.exe run
../z_tools/make.exe -r img
make.exe[1]: Entering directory `C:/TEST/test'
../z_tools/make.exe -r haribote.img
make.exe[2]: Entering directory `C:/TEST/test'
../z_tools/cc1.exe -I../z_tools/haribote/ -Os -Wall -quiet -o bootpack.gas bootp
ack.c
../z_tools/gas2nask.exe -a bootpack.gas bootpack.nas
skip:MOV ECX, [ESP+4]
skip:MOV AL,[ESP+8]
skip:MOV [ECX], AL
skip:RET
skip:HLTRET
make.exe[2]: *** [bootpack.nas] Error 1
make.exe[2]: Leaving directory `C:/TEST/test'
make.exe[1]: *** [img] Error 2
make.exe[1]: Leaving directory `C:/TEST/test'
..\z_tools\make.exe: *** [run] Error 2
C:\TEST\test>
です。
先ほどと違うのは、命令を、1つずつ認識している点です。
しかしスキップされています。
このスキップさえ止めればうまくいきそうです。
よろしくおねがいいたします。私もがんばります。
No.5
- 回答日時:
なんでいろいろと伏せる必要があるのか, さっぱりわからん. そのくらいやましいことをしているという自覚がある? あるいは, あえて情報量を減らすことによって回答者に不要な労力を強いるという策略?
さておき, #2 にもあるように「インラインアセンブラの構文はコンパイラごとに異なる」んだから, 自分の使っているコンパイラに合わせて書き直してください.
なお, インラインアセンブラに手を出すくらいなら「どう書き直せばいいのか」などという質問はしないように.
この回答への補足
回答くださりありがとうございます。伏せているのは、ただ単に私が臆病ものだからです。だったらこんなところに出てくるべきではないと、突っ込まれそうですが、どうしてもわからなかったから、ほかに良い方法がなかったのです。
>なお, インラインアセンブラに手を出すくらいなら「どう書き直せばいいのか」などという質問はしないように.
と、くぎを刺されましたが、最悪の場合、「どう書き直せばいいのか」を質問せねばなりません。そのためにこういうサイトがあるのではないでしょうか。
#5の方には、申し訳ないのですが、私に釘をさすことだけが目的に感じられ、私の質問の答えになっておりません。すでに#2の方の転記だけです。今後、こういった投稿をなさるのならば、私が疲れるので、無視しますので、ご了承ください。
No.4
- 回答日時:
検索すると、コロンのあとはレジスタの条件等を指定することとなっています。
だとすると、コロンの後に"MOV AL,[ESP+8]"といった命令があると、エラーになるのでは?
asmへの命令は、改行やセミコロンで区切ることになっていると思います。
C言語では、並べて描かれた文字列リテラルは連結されるので、
"MOV EAX,[ESP+4]"
"MOV AL,[ESP+8]"
"MOV [EAX],AL"
"RET"
は
"MOV EAX,[ESP+4]MOV AL,[ESP+8]MOV [EAX],ALRET"
と同じになるので、うまくいかないのでは? 検索してみると、命令の最後に\n\tを入れているコードを見かけます。
もしくは、コードがそのままコピーしてきたものなら、途中にマルチバイト文字(所謂全角文字)があるせいだとか。
使用するデータを、関数呼び出し時にスタックにある前提で取り出していますが、Cの変数をレジスタに設定する方法がある(前述のコロンを使用するもの)ので、そちらの方法にしたほうがいいように思いますが。
ちなみに、伏字で書いても、伏字部分が容易に推測できる場合には、法的責任を回避することはできません。
仮名で書かれた文章でも、内容から実在の人物が推測できるような場合に、プライバシーの侵害を認めた裁判例があります。
まあ、今回の内容なら、タイトルを堂々と書いても責任を問われるようなことはないでしょうが。
この回答への補足
回答ありがとうございます。私は、性分が臆病ものなので、書籍の名前を伏字で出すのも、ここに質問するのも、怖かったのですが、どうしても解決したくなり、質問するに至りました。
本論に入ります。
おっしゃっておられることが、的を得ていると思います。実際に、コロンなしでコンパイルするとエラーがおっしゃるとおりになりました。プログラムと、エラーメッセージを後で書いておきます。
コロンを使う方法で調べたのですが、グーグルにもあまりなくて、こういう場合どう書けばよいのか、具体例がないので、(あるのかもしれませんが私には見つけることができませんでした。)できれば、コロンありの場合を、どう書けばよかったのかを、ご教授願えないでしょうか。よろしくおねがいいたします。答えを聞くようで、こういうことを願い出るのはためらわれたのですが、もはや、私の頭の中がパニックに近い状態で、一体どの情報が正しいのかわからなくなっているので、何卒よろしくお願いいたします。
bootpack.c----------------------
static __inline__ void io_hlt2(void){
__asm __volatile (
"HLT"
"RET"
);
}
static __inline__ void write_mem82(int addr, int data){
__asm __volatile (
"MOVECX, [ESP+4]"
"MOVAL,[ESP+8]"
"MOV[ECX], AL"
"RET"
);
}
void main(void)
{
int i;
for (i = 0xa0000; i <= 0xaffff; i++) {
write_mem82(i, i & 0x0f);
}
for (;;) {
io_hlt2();
}
}
エラーメッセージーーーーーーーーーーーーーーーーーー
C:\TEST\test>make run
C:\TEST\test>..\z_tools\make.exe run
../z_tools/make.exe -r img
make.exe[1]: Entering directory `C:/TEST/test'
../z_tools/make.exe -r haribote.img
make.exe[2]: Entering directory `C:/TEST/test'
../z_tools/cc1.exe -I../z_tools/haribote/ -Os -Wall -quiet -o bootpack.gas bootp
ack.c
../z_tools/gas2nask.exe -a bootpack.gas bootpack.nas
skip:MOV ECX, [ESP+4]MOV AL,[ESP+8]MOV [ECX], A
LRET
skip:HLTRET
make.exe[2]: *** [bootpack.nas] Error 1
make.exe[2]: Leaving directory `C:/TEST/test'
make.exe[1]: *** [img] Error 2
make.exe[1]: Leaving directory `C:/TEST/test'
..\z_tools\make.exe: *** [run] Error 2
C:\TEST\test>
以上です。
よろしくお願いします。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# Cのオブジェクトファイルの逆アセンブル 5 2023/05/13 01:51
- その他(プログラミング・Web制作) x86_32のGASの擬似命令 3 2023/06/07 19:55
- C言語・C++・C# スタックフレームの消滅 6 2023/05/20 12:33
- C言語・C++・C# アセンブラ指令 3 2023/06/17 14:47
- C言語・C++・C# C言語 3 2022/10/04 15:07
- C言語・C++・C# 至急教えてください! プログラミングの問題です! お願いします! 出力2と全く同じ出力をするように、 2 2022/06/22 23:10
- Java javaでのプログラム(配列)について質問です. 2 2022/10/14 22:27
- C言語・C++・C# 10個の実数に対する降順ソート結果を出力するプログラムを作りたいのですが、以下のプログラムをどう直せ 1 2022/07/09 22:16
- C言語・C++・C# C言語プログラム変更 2 2022/12/21 15:03
- C言語・C++・C# c言語の問題です 課題1 (二分探索木とセット) 大きさ size の配列 array を考える。す 2 2023/01/10 21:08
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・「みんな教えて! 選手権!!」開催のお知らせ
- ・漫画をレンタルでお得に読める!
- ・【選手権お題その2】この漫画の2コマ目を考えてください
- ・2024年に成し遂げたこと
- ・3分あったら何をしますか?
- ・何歳が一番楽しかった?
- ・治せない「クセ」を教えてください
- ・【大喜利】看板の文字を埋めてください
- ・【大喜利】【投稿~12/17】 ありそうだけど絶対に無いことわざ
- ・【選手権お題その1】これってもしかして自分だけかもしれないな…と思うあるあるを教えてください
- ・【穴埋めお題】恐竜の新説
- ・我がまちの「給食」自慢を聞かせてっ!
- ・冬の健康法を教えて!
- ・一番好きな「クリスマスソング」は?
- ・集合写真、どこに映る?
- ・自分の通っていた小学校のあるある
- ・フォントについて教えてください!
- ・これが怖いの自分だけ?というものありますか?
- ・スマホに会話を聞かれているな!?と思ったことありますか?
- ・それもChatGPT!?と驚いた使用方法を教えてください
- ・見学に行くとしたら【天国】と【地獄】どっち?
- ・これまでで一番「情けなかったとき」はいつですか?
- ・この人頭いいなと思ったエピソード
- ・あなたの「必」の書き順を教えてください
- ・10代と話して驚いたこと
- ・14歳の自分に衝撃の事実を告げてください
- ・人生最悪の忘れ物
- ・あなたの習慣について教えてください!!
- ・都道府県穴埋めゲーム
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
アセンブラからC言語に変換する...
-
ライン数とステップ数の違いは?
-
バイナリの実行ファイルをgccを...
-
PC-9801でマシン語を学習するに...
-
PICに書き込むプログラムや変数...
-
PDP-11のアセンブラ課題
-
物理メモリの任意のアドレスを...
-
【H8マイコン】HEWで埋め込みア...
-
アセンブラ言語がわかりません。
-
このアセンブラの意味を教えて...
-
0xffffとは?
-
シーケンサのデータレジスタD...
-
三菱シーケンサーの命令でFROM ...
-
ビットシフトってどんな時使うの?
-
H8/3052マイコンについて
-
アセンブリ言語からC言語への変...
-
verilog 符号付加減算(最上位...
-
FFTの単精度と倍精度の計算時間
-
シーケンス制御についての質問...
-
8ビットのデータの、先頭ビット...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
アセンブラからC言語に変換する...
-
ライン数とステップ数の違いは?
-
実行ファイルからソースはみれる?
-
アセンブラ言語がわかりません。
-
アセンブラのLA
-
PC-9801でマシン語を学習するに...
-
[C言語→アセンブリ言語]はどう...
-
アセンブラwordという単位
-
アセンブラ言語で質問です。
-
アセンブラで割り算
-
PICに書き込むプログラムや変数...
-
バイナリの実行ファイルをgccを...
-
PICはアセンブラとC言語のどち...
-
SHの命令の意味について
-
MPLAB IDE v8.92アセンブラにつ...
-
【H8マイコン】HEWで埋め込みア...
-
素数を求めるプログラム(アセン...
-
IBM system/360
-
void __cdeclなど_
-
このアセンブラの意味を教えて...
おすすめ情報