• ベストアンサー

8086アセンブラで、メモリ間のデータをストリング命令でブロック転送したい

ソースが長めなので、簡潔に書きます。ご無礼の段、ご容赦ください。 【目的】PC-9801本体のCバス(汎用拡張スロット)に挿したサウンドボード上の ROM BIOSを読み出し、バイナリファイルに落としたい。既にエミュレータ用に実機からの 吸出しツールは存在するが、ソースが無いので、自作することにした。 その前段階としてアセンブラの修行も兼ねて、ROM BIOSの先頭3ワード(6バイト)を メモリ上のバッファにコピーし、比較して値の合致を確認したい。 将来的にはSCSI ROM BIOSの解析等を試みたい。 【方針】8086のストリング命令でダイレクトにメモリtoメモリでブロック転送を する。具体的にはrep movsbを用い、6バイトを転送する。 【備考】PC-9801-26K互換音源のROM BIOS(少なくとも先頭8バイト)は一意であり、 その並びは、0001h, 0000h, 00d2h である。例外はありません。 86音源でも同様で、下位互換性があることは、拙作ツール(OPNCHK.COM)にて確認済み。 なお、上記バイト列は、セグメントCC000h:オフセット2E00hから読み出し 可能である。 なお実行にあたり、所謂メモリマネージャの類(MELEMM.386等)は一切 組み込まない状態で行なう(EMSメモリマネージャ等との同居対応は将来の課題とします)。 【開発環境】PC-9801DA2(Cyrix Cx486DLC-25MHzに載せ換え; 13.6MB RAM; HA-55BS4 SCSIボード + 240MB SCSI HDD + SONY CPD-17SF9 CRT + NASM 2.06rc10 on NEC DOS 5.0A-H + Turbo Debugger v3.2 と、 秋葉で買ったジャンクFDに入ってたMASM ver 3.00; 予備機 VX41/RS21/EPSON 286VF/EPSON 486HX2/Xv13R16[K6-2 400MHz]/ AT互換機上のNekoIIエミュ/Cygwin上のnasmw.exe) 【参考書】PC-98、8086アセンブラ、テクニカルデータ、古雑誌等 定番本100冊ほど 【拙作コードの失敗点をご指南いただきたい。NASMコードですが、MASM/TASMでも構いません】 ; PC-9801-26K compatible Sound ROM BIOS Copy Program (i/o address 0188h) ; Programmed by OrzHacker666 ; Date 2009-07-13 for NASM 2.06rc10 [Bits 16] org 100h ; COM program section .text start: push es ; これを保存しないと、 push ds ; 画面がめちゃくちゃになる mov ax, 0cc00h ; Sound ROM セグメントアドレス mov es, ax mov ds, ax ; DS:SI -> ES:DI 無意味か? mov bx, 2e00h ; Sound ROM オフセットアドレス lea si, [es:bx] ; ES:BX がSound ROMの開始点 lea di, [ds:sbuff] ; sbuffは仮に確保したバッファ。 ; どこにあるかは、当たり前ですが、不明。そこら辺はCの変数宣言と同じですが。 mov cx, 8 ; とりあえず、アタマ8バイトをコピー cld rep movsb CompareWithOriginal: cmp word [es:bx+4], 00d2h ; これは通る。当たり前。 jne FailedCpyRom cmp word [ds:sbuff+4], 00d2h ; ここで失敗判定。なぜ? jne FailedCpyRom ; sbuffにes:bx~が正しく ; 転送されていないのか? SuccessCpyRom: ; これを拝めれば…。 pop ds pop es mov ah, 9 lea dx, [SUCCESSMsg] int 21h mov ax, 4c00h int 21h FailedCpyRom: ; 見飽きましたOrz pop ds pop es mov ah, 9 lea dx, [FAILEDMsg] int 21h mov ax, 4c00h int 21h section .data SUCCESSMsg: db 'Succeeded !!', 0dh, 0ah, '$' FAILEDMsg: db 'Failed(--;)', 0dh, 0ah, '$' section .bss sbuff: resb 8 ; Cで書くと、差し詰め unsigned char sbuff[8]; であろうか…。 識者の方、よろしくお願いいたします。気になって夜も眠れません。

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

  • ベストアンサー
  • nda23
  • ベストアンサー率54% (777/1415)
回答No.3

>回答中の、"cmp word es:[di-4], 00D2h"は MOVSD×2でDIはsbuff+8を指しています。DI-4はsbuff+4のことです。 これくらいはアセンブラをやる以上、直ぐに分かってください。 >sbuff自体については、セグメント値は不定で、調べる意義は無い ちょっと乱暴な話ですね。sbuffはbss(初期値なし静的領域)のよう なので、実行時のDSです。 確実なのはtextセグメント(コードと同じ)に次のようにデータを 定義して使います。 LES  DI,CS:adr 'ES:DIにsbuffのセグメント:オフセットが入る == 中略 == adr  DD sbuff 'sbuffのセグメント:オフセットが記録される >DS=ESではダメです だって、そうなっていますよ。AXをDSにもESにもMOVしてます。 前にも書いたんですが、セグメントの使い方が分かっていない? 前のサンプルは上記仮定(sbuffは実行時DSにある)で作っています。 PUSH DS、POP ES ES←DSにしています。(受け取り側が実行時DS) この後で、DSに0CC00hを代入しています。 >[es:]のオーバーライドは必須です CMP   WORD ES:[DI-4],00D2h ちゃんと、ESでオーバライドしてるはずですけどね。 >ジレンマに陥ります どこがでしょう?アセンブラで、セグメントレジスタを使う以上は 自分の自由に使えば良い訳で、適当に値を設定したり、戻したりすれば 済む話なのでは? 例: REP  MOVSB PUSH  DS PUSH  ES POP   DS POP   ES 後の4命令で、DSは実行時DSに戻り、ESはROMセグメントを指します。 サンプルではこれをやっていないので、実行時DSはESにある状態です。 故にセグメントオーバーライドしています。

maxsununix
質問者

お礼

試行錯誤の後、完成しましたので、ソースを掲載いたしまして終了いたします。 なお、この後にSound BIOS ROM 16KB全部を sbuff resw 8192 とした領域へ完全コピーすることに成功しました(別ソースですが)。 # あとは、DOSファンクションコールで、RAMからファイルへの # 読み書きを付け加えれば当初の目的は達成可能となります。 # ご指南ありがとうございました。 ; PC-9801 Sound BIOS Rom Copy Program(first 3 words(6 bytes) only) ; Programmed by OrzHacker666 ; ver 1.04 ; Date 2009-07-14 ; for NASM 2.06rc10 [Bits 16] org 100h ; COM program section .text start: push ds mov ax, 0cc00h ; Sound BIOS Segment Address mov ds, ax ; DS=CC00H mov bx, 2e00h ; Sound BIOS Offset Address lea si, [ds:bx] ; DS:SI points the Sound BIOS Address lea di, [sbuff] ; and store them on ES:DI (sbuff) mov cx, 3 ; copy first 6 bytes (3 words) cld rep movsw CompareWithOriginal: pop ds cmp word [sbuff], 0001h jne FailedCpyRom cmp word [sbuff+2], 0000h jne FailedCpyRom cmp word [sbuff+4], 00d2h ; Check if sbuff contains jne FailedCpyRom ; the original Sound BIOS Data SuccessCpyRom: mov dx, SUCCESSMsg mov ah, 9 int 21h mov ax, 4c00h int 21h FailedCpyRom: mov dx, FAILEDMsg mov ah, 9 int 21h mov ax, 4c00h int 21h section .data SUCCESSMsg: db 'Succeeded !!', 0dh, 0ah, '$' FAILEDMsg: db 'Failed(--;)', 0dh, 0ah, '$' section .bss sbuff resw 3 以上

全文を見る
すると、全ての回答が全文表示されます。

その他の回答 (2)

  • trapezium
  • ベストアンサー率62% (276/442)
回答No.2

>lea di, [ds:sbuff] ; sbuffは仮に確保したバッファ。 >; どこにあるかは、当たり前ですが、不明。そこら辺はCの変数宣言と同じですが。 いやcom programならcsと同じsegment上のオフセット値。なので、 >mov ax, 0cc00h ; Sound ROM セグメントアドレス >mov es, ax >mov ds, ax ; DS:SI -> ES:DI 無意味か? これだとやっぱり(3)ということになります。

maxsununix
質問者

補足

ご回答ありがとうございます。 あれから数時間格闘したのですが、自作のデバッグコードを 仕込んだりしてみた結果、以下のような中間結果が出ました。 まず、 1)sbuff自体については、セグメント値は不定で、調べる意義は無い。 強いて言えば、お二方ご指摘の通り、ROM領域にぶち当たらないように することでしょうか。ただし、ソース末尾に未定義領域として sbuff: resb 8 として確保しており、また、割り込み禁止状態でmov word [sbuff+4], 00d2hと強制書込した上で、 cmp word [sbuff+4], 00d2hが一致することを確認したので、 sbuffは確実にRAM領域に確保されていると考えられる(なにより、resb擬似命令で ROM領域にバイト列をリザーブするのは、NASMの仕様上あり得ないことなので。MASMでも同様でしょう)。 上記は、mov ds, axでES=DS=CC00Hとするのを止め、DS=初期値と した結果、書込成功したということです。 ご指南の通りにmov ds, axを廃止したところ、mov word [ds:sbuff], 00d2h でも mov word [sbuff], 00d2h でも、(バイト数の無駄の違いこそあれ)sbuffへの00d2hの値の書込みは正常に行なわれていることが確認されました。 2)コピー失敗時のセグメントレジスタおよびsbuffの値を追ったところ、 以下の通りであった:(DSは初期状態のままとした場合) DS = 1322H ES = CC22H sbuff = 0222H Q: DS/ES/sbuffともに、下1バイトが22Hとなっているが、これは どこからきた値なのか?ESの上1バイトがCCHとなっているのは、 最初にAXから代入した際(mov ax, 0cc00h/mov es, ax)から理解できる。 sbuffの上1バイトについては起動毎に変わる(不定域ですから)。 DSの13xxHについては、org 100hでCOM宣言した際のオリジナル値であり、 SSも同じ値であると思われる。これも、不定だと思います。 いま、参考書をひっくり返して思案しています。すみません。

全文を見る
すると、全ての回答が全文表示されます。
  • nda23
  • ベストアンサー率54% (777/1415)
回答No.1

セグメントオーバライドが間違っていますが、DS=ESなので、結果は 同じになります。 lea si, [es:bx] ; ES:BX がSound ROMの開始点 → MOV SI,BX セグメントオーバライドは無意味、1バイトと数クロックの損 cmp word [es:bx+4], 00d2h ; これは通る。当たり前。→ES:は不要 セグメントオーバライドは無意味、1バイトと数クロックの損 DS:送り出し側、ES:受け取り側です。ここまではDS=ESなら問題は ありません。送り出し側の+4と受け取り側の+4で内容が異なる となると、次の点が可能性として考えられます。 (1)割り込みにより、内容が書き換えられる。 (2)送り出し側と受け取り側のアドレスが一部で重複する。 (3)受け取り側がROMで、内容が変化しない。 個人的な見解としては(3)ではないかと思います。 転送先(sbuff)のセグメントがROMと同じなのがどうもアヤシイ PUSH  ES ;保存 PUSH  DS ;保存 PUSH  DS ;ES←DSのための第1ステップ POP   ES ;ES←DSのための第2ステップ MOV   AX,0CC00h MOV   DS,AX MOV   BX,2E00h MOV   SI,BX LEA   DI,sbuff CLD CLI ;念のため割り込み禁止にする MOVSD ;ダブルワード(4バイト)転送 MOVSD ;ダブルワード(4バイト)転送 CMP   WORD ES:[DI-4],00D2h STI ;割り込み許可 JNE   FailedCpyRom 上記は規定データセグメント上にsbuffがあるものと仮定しています。 もう一度、セグメントレジスタの使い方を見直してください。

maxsununix
質問者

お礼

お礼の欄で釈明することをお許しください。 #1)DS=ESなので、結果は同じになります。 A. DS=ESではダメです。ESはSound ROM BIOSのセグメントアドレスを 示すために、0cc00hを代入する必要があります。 MOV SI,BX としてしまうと、これは単にsiにbx(=2e00h)を代入するだけになってしまいます。ここで lea si, [es:bx]としているのは、siレジスタに、CC00H:2E00Hのアドレスを代入したいということなのです。 [es:]のオーバーライドを取り払ってしまえば、Sound ROMと無関係なBX(アドレス)がSIに入ってしまいます。 #2)cmp word [es:bx+4], 00d2h ; これは通る。当たり前。→ES:は不要 A. 同上の理由で、[es:]のオーバーライドは必須です。無関係のBXと00d2hは 一致しません。 Q. 結局、DSは初期値のままでいてほしい、かつESはSound ROMのセグメントアドレスを 示して、常にBXと共に用いる必要がある、というジレンマに陥ります。

maxsununix
質問者

補足

ご回答ありがとうございます。cli/sti対策をしてみました。 # 回答中の、"cmp word es:[di-4], 00D2h"は、sbuffのオフセットアドレスから 4バイト目の値と00d2hの比較の書き間違いでしょうか? # 正しくは、"cmp word es:[sbuff+4], 00d2h"もしくは、push di/pop diを movsbの前後に挟み込むしかないでしょうね。 # word [es:di+4]との比較ですと、さらに4バイト先まですっ飛んでしまいますので。 あれから数時間格闘したのですが、自作のデバッグコードを 仕込んだりしてみた結果、以下のような中間結果が出ました。 まず、 1)sbuff自体については、セグメント値は不定で、調べる意義は無い。 強いて言えば、お二方ご指摘の通り、ROM領域にぶち当たらないように することでしょうか。ただし、ソース末尾に未定義領域として sbuff: resb 8 として確保しており、また、割り込み禁止状態でmov word [sbuff+4], 00d2hと強制書込した上で、 cmp word [sbuff+4], 00d2hが一致することを確認したので、 sbuffは確実にRAM領域に確保されていると考えられる(なにより、resb擬似命令で ROM領域にバイト列をリザーブするのは、NASMの仕様上あり得ないことなので。MASMでも同様でしょう)。 上記は、mov ds, axでES=DS=CC00Hとするのを止め、DS=初期値と した結果、書込成功したということです。 ご指南の通りにmov ds, axを廃止したところ、mov word [ds:sbuff], 00d2h でも mov word [sbuff], 00d2h でも、(バイト数の無駄の違いこそあれ)sbuffへの00d2hの値の書込みは正常に行なわれていることが確認されました。 2)コピー失敗時のセグメントレジスタおよびsbuffの値を追ったところ、 以下の通りであった:(DSは初期状態のままとした場合) DS = 1322H ES = CC22H sbuff = 0222H Q: DS/ES/sbuffともに、下1バイトが22Hとなっているが、これは どこからきた値なのか?ESの上1バイトがCCHとなっているのは、 最初にAXから代入した際(mov ax, 0cc00h/mov es, ax)から理解できる。 sbuffの上1バイトについては起動毎に変わる(不定域ですから)。 DSの13xxHについては、org 100hでCOM宣言した際のオリジナル値であり、 SSも同じ値であると思われる。これも、不定だと思います。 いま、参考書をひっくり返して思案しています。すみません。

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • NASM(独習アセンブラのサンプルソース)について

    独習アセンブラ初版5刷のサンプルソース(リスト6.7、102p)での疑問です 下の方にあるコメントアウトしているputc関数って何のためにあるんですか? どこからも呼び出してないのでいらないと思うのですが… アセンブラはNASMです ※本に書かれてるソースはコメントアウトしてません、コメントアウトしてもアセンブルできました bits 16 org 100h mov dx,sfile mov al,0 mov ah,3dh int 21h jc endquit mov [ifh],ax mov dx,dfile mov cx,0 mov ah,3ch int 21h jc endquit mov [ofh],ax readb: mov bx,[ifh] mov dx,buf mov cx,1 mov ah,3fh int 21h test cx,ax jz endquit jc endquit mov bx,[ofh] mov dx,buf mov cx,1 mov ah,40h int 21h jmp readb endquit: mov bx,[ifh] mov ah,3eh int 21h mov bx,[ofh] mov ah,3eh int 21h mov ax,4c00h int 21h ;putc: ; push ax ; mov ah,2h ; int 21h ; pop ax ; ret ifh dw 0 ofh dw 0 sfile db "srcfile.txt",0 dfile db "destfile.txt",0 buf resb 2 私が思うにリスト6.6(100p)のreadbラベルのところでこれを呼び出してるのでソースを流用して消し忘れてるだけなんでしょうか?

  • アセンブラ、ファンクションコールの使い方

    入力した一文字を改行して表示させるものを作ってます。 以下のものを書いてみまして、 一文字読み取って改行はしますが表示されません。 アドバイス頂けますでしょうか? 環境は MASM 32 です。 name double .model small .stack 100 .data prompt db 0ah,0dh,"? $" .code start: mov ax, @data mov ds, ax lea dx, prompt mov ah, 9 ;output string int 21h mov ah, 1 ;get keyboard input and store into al int 21h mov dl, 0ah mov ah, 2 int 21h mov dl, 0dh mov ah, 2 int 21h mov dl, al mov ah, 2 ;output char from dl int 21h mov ax, 4c00h ;exit int 21h end start

  • BIOSによる表示

    こんばんわ。お世話になります。 今, 自分はフロッピーをさした状態でPCの電源を入れるとそのフロッピーに格納されているプログラムが動くようにしたいと思っています。 その手始めとして, 文字を表示させたいのですが, どうもよくわかりません。 今までに自分は mov ah,0 mov al,03 int 10h で画面設定をし, mov ax,b800 mov es,ax mov di,0 mov byte ptr es:[di],41 mov ax,ff00 int 10h hlt なんてアセンブラを書きましたがwindows付属のdebugではこれはコンパイルできません。コンパイルできたと仮定して, これをrawriteでフロッピーに書き込むつもりです。 現在, 私のもとにある最も簡単なアセンブラはdebugです。nasmもありますが, 不勉強のため 使い方が良くわかりません。 有効なソースをお教えください。よろしくお願いします。

  • アセンブリ言語で。

    下のようなソースをアセンブルすると 6:error: parser: instruction expected という、エラーが出ます。 mov ah,2 mov dl,DATA int 21h mov ax,4c00h int 21h DATA byte 'A' 6行目に問題があるようなので下のように書き直したらきちんと動作しました。どうして、上のような記述ではうまくいかないのでしょうか?? mov ah,2 mov dl,'A' int 21h mov ax,4c00h int 21h 環境はwindowsXPでnasmとalinkを使っています。 nasmw test.asm -fobj alink test.obj -oEXEとしてアセンブルしました。 わかる方お願いいたします。

  • アセンブラ、ビデオモード al 13h でマウスのポインタを表示

    mov ah, 0 mov al, 13h int 10h のモードでマウスのポインタを表示することは可能でしょうか? 以下のコードを書いてみまして、ビデオモードを設定しない場合は Alt + Enter でフルスクリーンにすればポインタが表示されます。 環境は masm32、interrupt のリストはこちらです ↓ http://www.ctyme.com/intr/int.htm ---------------------------------- .model small .stack 100h .data .code start: mov ax, @data mov ds, ax mov ah, 0 ; set video mode mov al, 13h int 10h ; mov ax, 0 ; reset ; int 33h ; mov ax, 20h ; int 33h mov ax, 1 ; show mouse pointer int 33h mov ah, 1 ; wait for key int 21h mov ah, 0 ; restore video mode mov al, 3h int 10h mov ax, 4c00h ; exit int 21h end start

  • メモリデータ比較中にハング

    メモリデータ比較中にハング A領域のデータとB領域のデータを先頭から比較するプログラムをアセンブラで組んでおります。 しかしかなりの頻度でプログラムがハングし、困っております。 ソースを眺めていても、どこが悪いのかわかりません。ハングの原因をうまく調べる方法はあるでしょうか? 動作環境:MS-DOS アセンブラ:MASM32 MOV ECX, srcAddr;Aのメモリアドレス PUSH ECX POP ESI MOV ECX, dstAddr;Bのメモリアドレス PUSH ECX POP EDI MOV ECX, CmpByte;比較するバイト数(比較するのは100000Hexバイト) XOR EAX, EAX CALL ENTER_PROTECT;プロテクトモードに移行 CALL GET_SORC_SEL;SORC_SELのBASE AddressとLimitを変更 CALL GET_DEST_SEL;DEST_SELのBASE AddressとLimitを変更 ; DWORD単位で比較するので2で割る SHR ECX, 2 @@compare: CLD ;CMPS*でのESI,EDIの変化を増加方向に @@cmp4: CMPSD DS:[ESI], ES:[EDI] ;4Byteずつ比較 jne @@err4 dec ECX jnz @@cmp4 ; 4で割った余り分のチェック MOV ECX, CmpByte AND ECX, 3 or ecx, ecx jz @@exit jmp @@cmp1 @@err4: ; 1Byteずつチェックしてコンペアエラーしたオフセットを割り出す LEA ESI,[ESI-4] ; コンペアエラー前のオフセットに戻す LEA EDI,[EDI-4] shl ecx, 2 @@cmp1: ;1Byteずつ比較 CMPSB DS:[ESI], ES:[EDI] jne @@exit dec ECX jnz @@cmp1 @@exit: ; コンペアしたByte数を計算(EAX <- CmpByte - ECX) MOV EAX, CmpByte SUB EAX, ECX PUSH EAX CALL FREE_SORC_SEL CALL FREE_DEST_SEL CALL LEAVE_PROTECT POP AX POP BX MOV DX, BX RET _MemCmp2 ENDP

  • NASMが動かない。

    NASMをwindows7にインストールしました。 次のようなソースをmathandcomp.asmというファイル名で保存し、 コマンド・プロンプトで nasm mathandcomp.asm -o mathandcomp.com のようにすると、mathandcomp.comが生成されるそうですが、エラーが出てしまいます。 下記のメッセージが出るはずなんですが、手順をおしえていただけますか。 NASMのバージョンはnasm-2.08.01です。 http://www.nasm.us/ org 100h mov dx,mesg mov ah,9 int 21h mov ah,4Ch int 21h mesg db 'Math with PC,PC through Math! How wonderful!',0Dh,0Ah,'$'

  • アセンブラ(二度目)

    先ほど質問させていただいたのですが、NASMでobjファイルを出力して、 ALINKをつかってexeファイルを出力したのですが、その際結果を確認するのに邪魔なものが一緒に出力されました。 ソースはこれです。 segment code ..start: mov ax, data mov ds, ax mov ax, stack mov ss, ax mov sp, stacktop mov dx, hello mov ah, 0x09 int 0x21 mov ax, 0x4c00 int 0x21 segment data hello: db 'Hello World',13,10,'$' segment stack stack resb 64 stacktop:

  • アセンブラを実行したいのですが

    パソコン初心者です。 Windows XPにアセンブラ「NASM」をダウンロードしました。 コマンドプロンプトで簡単なプログラムを実行しようと思います。 以下がプログラムです。 ; dispchar.asm mov ah,02 mov dl,31h int 21h mov ah,4ch mov al,0 int 21h コマンドプロンプトに「; dispchar.asm」と入力すると、内部コマンド、外部コマンドまたは操作可能なファイル、バッチファイルとして認識されていません」と出ます。 同様に、「mov ah,02」から入力しても同様のコメントが返ってきます。 プログラムを実行するにはどうすればよいでしょうか?

  • アセンブラできません。

    初心者です。 アセンブリ言語で1~9の数字を連続的に表示するプログラムを書いたのですが、アセンブラする時 「error A2016 expression expected」というエラーメッセージが出てアセンブラすることができません。 プログラムの内容は下記↓のものです。 何が原因でしょうか? CODE SEGMENT ASSUME DS:CODE,CS:CODE,ES:CODE,SS:CODE ORG 100h START: mov bl,30h jmp aa aa: mov ah,02h mov dl,bl int 21h mov ah,06h mov dl,0ffh int 21h jnz bb: mov ah,02h mov dl,08h int 21h inc bl cmp bl,39h ja START jmp aa bb: int 20h CODE ENDS END START

LenovoIDにログインできない
このQ&Aのポイント
  • LenovoIDにログインできず、パスワード再設定してもアカウントがロックされる問題について
  • IdeaPad L340-15APIのWindows10 v2004を使用しているが、LenovoIDにログインできない
  • LenovoノートブックのユーザーがLenovoIDにログインできず、アカウントがロックされるという問題が発生している
回答を見る

専門家に質問してみよう