• ベストアンサー

アセンブリ言語の質問です

「 100人分の試験点数がある。 一人分のデータは32bit 符号無し整数でそれが連続して格納されている.先頭のアドレスがEAXで与えられる時,全員の点数の合計をEAXに入れて戻るようなサブルーチンをアセンブリ言語で書きなさい。 • loop unrollingを使用して,ループ内容を4倍に展開して,条件分岐数を減らすこと • 他のレジスタの値は保存すること • 合計点はEAXレジスタに十分納まるものとする。 • 次のような命令を使ってよい。 ADD EAX, [EBX] 」 というような問題が出て自分で解答を作ってみたのですがこれでよいのでしょうか?詳しい方ご検討よろしくお願いいたします。 PUSH EBX(EBXをスタックにおいておく) PUSH ECX(ECXをスタックにおいておく) MOV ECX 25(ECXに25を代入。4回の操作を25回すれば100回になるからである。) label0:ADD EAX [EAX] ([EAX]をEAXに加算) ADD EAX [EAX+1]([EAX+1]をEAXに加算) ADD EAX [EAX+2]([EAX+2]をEAXに加算) ADD EAX [EAX+3]([EAX+3]をEAXに加算) MOV [EAX] [EAX+4]([EAX]を[EAX+4]に移動させる) EBX=EBX+1 (EBXはこのループを何回やったか、という数) CMP ECX EBX(25とEBXを比べる) JNZ:label0(比べてEBXが25になってないならば繰り返す。25になったら終了。) POP EBX(EBXをスタックから戻す) POP ECX(EBXをスタックから戻す)

質問者が選んだベストアンサー

  • ベストアンサー
  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.5

Intel の表記を使った上での「ソース上の間違い」は ・MOV ECX 25 など複数オペランド命令は各オペランドを「,」で区切る ・JNZ:label0 の「:」はいらない ・メモリ間の転送命令は存在しない ・EBX=EBX+1 って, なぜここだけこんな表記なのか くらいかな. といってもこれらは「アセンブルすれば一瞬でわかる」程度の, ある意味では「ど~でもいい」間違い. #2 の「加算が間違っている」は本質的. これは CPU の気持ちになって処理をすればわかるはず. もうちょっと言うと ・ADD EAX, [EAX] とやったときに EAX はどう変化するか ・EAX+1 がどこを指しているか を考えること. でも, この処理で「比較して分岐」ってやるのかなぁ? loop 使った方が簡単な気がする.

ararabre
質問者

お礼

具体的なご指摘ありがとうございます。 自分なりに試行錯誤してみたところ、できました。

その他の回答 (5)

  • memphis
  • ベストアンサー率40% (975/2395)
回答No.6

No,2ですが、 加算している所を良く見て下さい。 出題している問題の解答になるような加算をしていません。 チェックする時は、実際にどういうように値が入るかを考えれば 何が間違っているか気が付くはずです。 各レジスタにサンプルとして値を入れてみて考えて見て下さい。 結果が、まったく変な値になることに気が付くはずです。

ararabre
質問者

お礼

そうでした、これでは同じ加算を続けてしまいますよね。 ありがとうございました。

  • R32C
  • ベストアンサー率39% (115/290)
回答No.4

_______JZ______LBL01___________; Is Count Up ? No,GOTO LBL01  X --> _______JNZ______LBL01___________; Is Count Up ? No,GOTO LBL01 でした。

ararabre
質問者

お礼

ありがとうございます。

  • R32C
  • ベストアンサー率39% (115/290)
回答No.3

Intelではないど、某社のアセンブラなら こんな感じかな? ちょっと文法がでたらめですが。。。 見栄えが悪いですが、スペースを_アンダーバーにしてます。 ------------------------------------------------------------- ________PUSHM___R1,R2___________; R1,R2 save to Stack ________MOV.L___#25,R1__________; Loop Count ________MOV.L___#0,R2___________; Init Sum data to Zero LBL01: ________ADD.L___[R0],R2_________; 00+ ________ADD.L___4[R0],R2________; 04+ ________ADD.L___8[R0],R2________; 08+ ________ADD.L___12[R0],R2_______; 12+ ________ADD.L___#16,R0__________; Address += 16 ________SUB.L___#1,R1___________; Counter-- ________JZ______LBL01___________; Is Count Up ? No,GOTO LBL01 END: ________MOV.L___R2,R0___________; Sum data Output To R0 register ________POPM____R1,R2___________; Regster Restore ________RTS

  • memphis
  • ベストアンサー率40% (975/2395)
回答No.2

正常に動きません。 無駄なこともあるし、加算も間違っています。

ararabre
質問者

お礼

ありがとうございます。 どのように間違っているでしょうか?

  • A88No8
  • ベストアンサー率52% (834/1602)
回答No.1

こんにちは 詳しいことは判らないですけど、POPの順序が逆では?

ararabre
質問者

お礼

そうでした、ありがとうございます。

関連するQ&A

  • アセンブリ言語について。

    これが何をしているのか教えていただけないでしょうか?すみません。 これの事です。 (機械語データ) (アセンブリ言語) b8 57 61 6b 61 mov $0x616b6157,%eax 53 push %ebx 50 push %eax ba 04 00 00 00 mov $0x4,%edx bb 01 00 00 00 mov $0x1,%ebx b8 04 00 00 00 mov $0x4,%eax 89 e1 mov %esp,%ecx cd 80 int $0x80 58 pop %eax 31 c0 xor %eax,%eax 5b pop %ebx c3 ret

  • 機械語とアセンブリ言語について。

    (機械語データ) (アセンブリ言語) b8 57 61 6b 61 mov $0x616b6157,%eax 53 push %ebx 50 push %eax ba 04 00 00 00 mov $0x4,%edx bb 01 00 00 00 mov $0x1,%ebx b8 04 00 00 00 mov $0x4,%eax 89 e1 mov %esp,%ecx cd 80 int $0x80 58 pop %eax 31 c0 xor %eax,%eax 5b pop %ebx c3 ret こちらのアセンブリ言語の命令がわかるおすすめの書籍を知らないでしょうか? 教えていただけないでしょうか?すみません。

  • 機械語とアセンブリ言語について。

    (機械語データ) (アセンブリ言語) b8 57 61 6b 61 mov $0x616b6157,%eax 53 push %ebx 50 push %eax ba 04 00 00 00 mov $0x4,%edx bb 01 00 00 00 mov $0x1,%ebx b8 04 00 00 00 mov $0x4,%eax 89 e1 mov %esp,%ecx cd 80 int $0x80 58 pop %eax 31 c0 xor %eax,%eax 5b pop %ebx c3 ret で、右側のアセンブリ言語のニーモニックとオペランドについて解説していただけないでしょうか?すみません。

  • アセンブリ言語について。

    >2進数の羅列では人間にはあまりに読み書きしにくいからです。 >それを命令単位に区切って、英単語を元にした名前を与えたのが、 >アセンブリ言語です。 ニーモニックとは、その命令の名前の事です。 簡潔に要点がまとまっている、すばらしい説明ですね。その通りです。 これで理解できないなら、追加の説明のしようがありません。 (なお、このように、他人の発言は引用符を付けて引用すると、わかりやすくなります。是非そうしてください。) まあ具体例を挙げるならこんな感じ。 (機械語データ) (アセンブリ言語) b8 57 61 6b 61 mov $0x616b6157,%eax 53 push %ebx 50 push %eax ba 04 00 00 00 mov $0x4,%edx bb 01 00 00 00 mov $0x1,%ebx b8 04 00 00 00 mov $0x4,%eax 89 e1 mov %esp,%ecx cd 80 int $0x80 58 pop %eax 31 c0 xor %eax,%eax 5b pop %ebx c3 ret 人間がCPUを直接動かすプログラムを書こうとするとき、アセンブリ言語を使って書きます(右側の部分)。 mov $0x616b6157,%eax push %ebx push %eax mov $0x4,%edx mov $0x1,%ebx mov $0x4,%eax mov %esp,%ecx int $0x80 pop %eax xor %eax,%eax pop %ebx ret そしてこれをアセンブルすると、1対1対応した機械語のデータ列が出来ます。 それが b8 57 61 6b 61 53 50 ba 04 00 00 00 bb 01 00 00 00 b8 04 00 00 00 89 e1 cd 80 58 31 c0 5b c3 この部分。 機械語には改行なんてありませんから、実際は一連の b8 57 61 6b 61 53 50 ba 04 00 00 00 bb 01 00 00 00 b8 04 00 00 00 89 e1 cd 80 58 31 c0 5b c3 と言うデータ列になります。 これをCPUが実行していきます。 相当熟練した人で無ければ、このデータ列を見るだけでプログラム構造を理解する、というわけに行きません。 なので、人間が機械語レベルでプログラミングする際には、アセンブリ言語を使います。 ※この回答のプログラムはこちらから引用しました。 >31バイトでつくるアセンブラプログラミング アセンブラ短歌の世界 >https://book.mynavi.jp/support/pc/4946/c01_assembra.pdf で、機械語データは、なぜ、0と 1だけではないのでしょうか?教えていただけないでしょうか?すみません。

  • 機械語に直すことについて。

    (機械語データ) (アセンブリ言語) b8 57 61 6b 61 mov $0x616b6157,%eax 53 push %ebx 50 push %eax ba 04 00 00 00 mov $0x4,%edx bb 01 00 00 00 mov $0x1,%ebx b8 04 00 00 00 mov $0x4,%eax 89 e1 mov %esp,%ecx cd 80 int $0x80 58 pop %eax 31 c0 xor %eax,%eax 5b pop %ebx c3 ret これのintと movとxor の機械語が分かりません。後、retの機械語が、farなのかnearなのかも分かりません。教えていただけないでしょうか?すみません。

  • アセンブリ言語の宿題がわかりません。

    爆弾を解除するプログラムです。exeファイルしか与えられていません。 phase1から5まであり、それぞれにインプットを求められ、正しいインプット(解除コード)を入力すると解除できます。 間違ったコードを入力すると爆発してしまいます。1,2は解けましたが、3で躓きました。objdumpしてみて、あるstring(恐らくglobal定数)と同じインプットをすれば解除できると踏んだのですが、どうしてもその特定のstringがわかりません。 以下にobjdumpした内の一部を載せておきました。都合上最小限のコードだけ載せざるを得ませんでしたので、 下記URLに、exeファイル、逆アセンブルファイル、phase1,2のanswerをアップロードしております。お時間があれば是非ご協力をお願いします。 環境 OS:ubuntu 9.04 デバッガ:Gnu DeBugger 08048424 <_IO_getc@plt>: 8048424: ff 25 10 a0 04 08 jmp *0x804a010 804842a: 68 20 00 00 00 push $0x20 804842f: e9 a0 ff ff ff jmp 80483d4 <_init+0x18> 08048723 <phase_3_of_5>: 8048723: 55 push %ebp 8048724: 89 e5 mov %esp,%ebp 8048726: 57 push %edi 8048727: 56 push %esi 8048728: 53 push %ebx 8048729: 83 ec 1c sub $0x1c,%esp 804872c: a1 30 a0 04 08 mov 0x804a030,%eax 8048731: 89 04 24 mov %eax,(%esp) 8048734: e8 eb fc ff ff call 8048424 <_IO_getc@plt> 8048739: bb 00 00 00 00 mov $0x0,%ebx 804873e: 8d 75 e6 lea -0x1a(%ebp),%esi 8048741: eb 04 jmp 8048747 <phase_3_of_5+0x24> 8048743: 88 44 33 ff mov %al,-0x1(%ebx,%esi,1) 8048747: a1 30 a0 04 08 mov 0x804a030,%eax 804874c: 89 04 24 mov %eax,(%esp) 804874f: e8 d0 fc ff ff call 8048424 <_IO_getc@plt> 8048754: 83 f8 0a cmp $0xa,%eax 8048757: 74 06 je 804875f <phase_3_of_5+0x3c> 8048759: 43 inc %ebx 804875a: 83 fb 0f cmp $0xf,%ebx 804875d: 75 e4 jne 8048743 <phase_3_of_5+0x20> 804875f: c6 45 f3 00 movb $0x0,-0xd(%ebp) 8048763: 8d 75 e6 lea -0x1a(%ebp),%esi 8048766: bf e4 8b 04 08 mov $0x8048be4,%edi 804876b: b9 0d 00 00 00 mov $0xd,%ecx 8048770: fc cld 8048771: f3 a6 repz cmpsb %es:(%edi),%ds:(%esi) 8048773: 0f 97 c2 seta %dl 8048776: 0f 92 c0 setb %al 8048779: 38 c2 cmp %al,%dl 804877b: 74 0c je 8048789 <phase_3_of_5+0x66> 804877d: c7 04 24 03 00 00 00 movl $0x3,(%esp) 8048784: e8 31 fe ff ff call 80485ba <explode> 8048789: 83 c4 1c add $0x1c,%esp 804878c: 5b pop %ebx 804878d: 5e pop %esi 804878e: 5f pop %edi 804878f: 5d pop %ebp 8048790: c3 ret

  • アセンブラの読み方

    お世話になります。 アセンブラを勉強しています。 下記について教えていただけないでしょうか。 よろしくお願いいたします。 1 .file 2 .data 3 var: .long 0x1234 4.text 5 .global main 6 main: 7 movb $1, %al // 値1をレジスタalに代入 8 push %eax // レジスタeaxの内容をスタックに格納 9 call IncReg // 関数呼び出し 10 pop %eax // スタックからレジスタeaxに引き出し 11 push var // 変数varの内容をスタックに格納 12 call IncReg // 関数呼び出し 13 pop %ecx // スタックからレジスタecxに引き出し 14 ret // リターン 15 IncReg: 16 movl %esp, %ebp // pushによって動いたスタックの先頭アドレスをレジスタ ebp に代入 17 movl 4(%ebp), %edx // mainから渡された eax(var) の値をレジスタ edx に代入 18 incw %edx // レジスタ edx の値を2増やす 19 movl %edx, 4(%ebp) // 2増やしたものを引数のあるスタックの場所に代入 20 ret // リターン (質問) 7 でレジスタ al に 1 を代入したのは何か意味があるのでしょうか。 17 の4(%ebp)はスタックポインタの1つ下、つまりmainから渡された引数でよろしいでしょうか。 18 の incw %edx はレジスタ edx の値を 2 増やすという意味でよろしいでしょうか。 13 でレジスタ ecx の値は 1236 になるので正しいでしょうか。

  • アセンブリ言語のプログラム方法がわかりません!!

    アセンブリ言語の問題です。 スタックを使って、接尾辞(Postfix)で数式を計算するプログラムを作ってください。 足し算(add)、引き算(subtract)、掛け算(multiply)は二進化十進表現で計算します。 足し算は'+', 引き算は'-', 掛け算は'*',そして終了を'$'で表します。 計算は8-bitの2の補数をつかって行います。 例えば、 expression: .db 3,9,4,6,'+','-',2,'-','+','$' push 3,9,4,6 (stack: 6 4 9 3) pop 6 and 4, add, push 10 (stack: 10 9 3) pop 10 and 9, subtract, push -1 (stack: -1 3) push 2 (stack: 2 -1 3) pop 2 and -1, subtract, push -3 (stack: -3 3) pop -3 and 3, add, push 0 (stack: 0) pop the 0 into register r0 and stop. というような計算を実行するプログラムを作ってください。 よろしくお願いします。 できればAVR studioを使ってプログラミングしてほしいです。

  • これらの文を意味のわかる分にしてください

    アドレス          ダンプ    逆アセコード 00551A90 31C9 XOR ECX,ECX 00551A92 51 PUSH ECX 00551A93 E8 68575000 CALL 00A57200 00551A98 59 POP ECX 00551A99 41 INC ECX 00551A9A 83F9 02 CMP ECX,2 00551A9D 75 F3 JNZ SHORT 00551A92 00551A9F 31C0 XOR EAX,EAX 00551AA1 C2 0400 RETN 4 00551AA4 90 NOP 00551AA5 ゞ 00551AA6 ゞ 00551AA7 ゞ 00551AA8 ゞ 00551AA9 90 NOP 00551AAA 8B4424 04 MOV EAX,[ESP+4] 00551AAE 8B48 04 MOV ECX,[EAX+4] 00551AB1 8B10 MOV EDX,[EAX] 00551AB3 8B40 08 MOV EAX,[EAX+8] 00551AB6 51 PUSH ECX 00551AB7 52 PUSH EDX 00551AB8 50 PUSH EAX 00551AB9 E8 12BB2B00 CALL 0080D5D0 00551ABE 83C4 0C ADD ESP,C 00551AC1 33C0 XOR EAX,EAX 00551AC3 C2 0400 RETN 4

  • C言語->アセンブリ->C言語で構造体渡し

    OS開発をしています。 たとえば、 typedef struct test{ int t1; int t2; int t3; int t4 int t5; }test; という構造体があったとして、 ----アプリケーション---- void main(){ test data; data.t1=100; data.t5=200; testint(data); } ----ライブラリ(アセンブリ)---- _testint: PUSH EBX MOV EBX,ESP INT 0x52 POP EBX RET ----OS側---- int API(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax){ test data; data= *(((int *)ebx) + ?); … // ↑ } というプログラムのとき、 ?には、どのような数字を入れれば、 OS側のdataにアプリ側のdataが代入できるでしょうか。 test構造体のサイズは、 20Byteです。 長い質問ですが、回答お願いします。

専門家に質問してみよう