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で質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・漫画をレンタルでお得に読める!
- ・【大喜利】【投稿~11/12】 急に朝起こしてきた母親に言われた一言とは?
- ・好きな和訳タイトルを教えてください
- ・うちのカレーにはこれが入ってる!って食材ありますか?
- ・好きな「お肉」は?
- ・あなたは何にトキメキますか?
- ・おすすめのモーニング・朝食メニューを教えて!
- ・「覚え間違い」を教えてください!
- ・とっておきの手土産を教えて
- ・「平成」を感じるもの
- ・秘密基地、どこに作った?
- ・【お題】NEW演歌
- ・カンパ〜イ!←最初の1杯目、なに頼む?
- ・一回も披露したことのない豆知識
- ・これ何て呼びますか
- ・チョコミントアイス
- ・初めて自分の家と他人の家が違う、と意識した時
- ・「これはヤバかったな」という遅刻エピソード
- ・これ何て呼びますか Part2
- ・許せない心理テスト
- ・この人頭いいなと思ったエピソード
- ・牛、豚、鶏、どれか一つ食べられなくなるとしたら?
- ・あなたの習慣について教えてください!!
- ・ハマっている「お菓子」を教えて!
- ・高校三年生の合唱祭で何を歌いましたか?
- ・【大喜利】【投稿~11/1】 存在しそうで存在しないモノマネ芸人の名前を教えてください
- ・好きなおでんの具材ドラフト会議しましょう
- ・餃子を食べるとき、何をつけますか?
- ・あなたの「必」の書き順を教えてください
- ・ギリギリ行けるお一人様のライン
- ・10代と話して驚いたこと
- ・家の中でのこだわりスペースはどこですか?
- ・つい集めてしまうものはなんですか?
- ・自分のセンスや笑いの好みに影響を受けた作品を教えて
- ・【お題】引っかけ問題(締め切り10月27日(日)23時)
- ・大人になっても苦手な食べ物、ありますか?
- ・14歳の自分に衝撃の事実を告げてください
- ・架空の映画のネタバレレビュー
- ・「お昼の放送」の思い出
- ・昨日見た夢を教えて下さい
- ・ちょっと先の未来クイズ第4問
- ・【大喜利】【投稿~10/21(月)】買ったばかりの自転車を分解してひと言
- ・メモのコツを教えてください!
- ・CDの保有枚数を教えてください
- ・ホテルを選ぶとき、これだけは譲れない条件TOP3は?
- ・家・車以外で、人生で一番奮発した買い物
- ・人生最悪の忘れ物
- ・【コナン30周年】嘘でしょ!?と思った○○周年を教えて【ハルヒ20周年】
- ・あなたの習慣について教えてください!!
- ・都道府県穴埋めゲーム
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
ライン数とステップ数の違いは?
-
アセンブラからC言語に変換する...
-
アセンブラ言語がわかりません。
-
アセンブラwordという単位
-
素朴な疑問 (C言語とアセン...
-
アセンブラエディタ
-
PICに書き込むプログラムや変数...
-
アセンブラのLA
-
【H8マイコン】HEWで埋め込みア...
-
YellowIDE6でのコンパイルについて
-
8ビットのデータの、先頭ビット...
-
0xffffとは?
-
スロースキャンコンピュータ 加...
-
レジストってなんですか?
-
エクセルVBAのIf,Then 構...
-
ビットシフトってどんな時使うの?
-
C言語で128bitの2進数のビット...
-
CPUのビット数と、メモリ(主記...
-
一般のソフトで画像を扱う場合...
-
PS3に搭載されている"Cell"は、...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
ライン数とステップ数の違いは?
-
アセンブラからC言語に変換する...
-
実行ファイルからソースはみれる?
-
アセンブラ言語がわかりません。
-
素数を求めるプログラム(アセン...
-
[C言語→アセンブリ言語]はどう...
-
PICはアセンブラとC言語のどち...
-
PICのアセンブラからC言語へ変...
-
PICに書き込むプログラムや変数...
-
アセンブラの配列処理
-
アセンブラのLA
-
IBM system/360
-
PC-9801でマシン語を学習するに...
-
アセンブラエディタ
-
void __cdeclなど_
-
アセンブリ言語について。
-
YellowIDE6でのコンパイルについて
-
アセンブラで割り算
-
アセンブラ言語で
-
アセンブラ言語で質問です。
おすすめ情報