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

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

新規登録して質問してみよう
ただいま回答率
85.48%
アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

Q&A

3回答

2311閲覧

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

stack_hack

総合スコア10

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

0グッド

1クリップ

投稿2015/03/02 20:19

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

count.datのファイルから数値を読み取ってインクリメントするプログラムなのですが
以下のコードのCOUNT_INC:からの処理がいまいちモヤモヤします

どなたか詳しくご教授頂けないでしょうか

//-----------------
org 100Hsection .data

FILENAME db 'count.dat', 00H
ERRORTEXT1 db 'ERROR OPEN', 00H
ERRORTEXT2 db 'ERROR READ', 00H
ERRORTEXT3 db 'ERROR WRITE', 00H
CONTENTTYPE db 'Conyent-Type: text/html', 0DH, 0AH, 0DH, 0AH, 00H

section .bss

buffer: resb 64
datalen: resw 1
handle: resw 1

section .text
start:
mov bx, CONTENTTYPE
call PRINT

FILE_OPEN:
mov ax, 3D02H
mov dx, FILENAME
int 21H
jnc FILE_OPEN_OK
mov bx, ERRORTEXT1
call PRINT
jmp PROGRAM_END

FILE_OPEN_OK:
mov [ds:handle], ax

MEN_CLR:
xor ax, ax
mov bx, buffer
mov cx, 64

MEM_CLR_1:
mov [ds:bx], al
inc bx
loop MEM_CLR_1

FILE_DATA_READ:
mov ax, 3F00H
mov cx, 64-1
mov dx, buffer
mov bx, [ds:handle]
int 21H
jnc FILE_READ_OK
mov bx, ERRORTEXT2
call PRINT
jmp PROGRAM_END

FILE_READ_OK:
mov [ds:datalen], ax

COUNT_INC:
mov si, buffer
mov di, buffer
add di, [ds:datalen]

INC_DIGIT:
cmp si, di
jz INC_DIGIT_1
dec di
mov al, [ds:di]
cmp al, '9'
jnz INC_DIGIT_2
sub al, 9
mov [ds:di], al
jmp INC_DIGIT

INC_DIGIT_1:
mov cx, [ds:datalen]
mov si, buffer
add si, cx
mov di, si
dec si
std

INC_DIGIT_LOOP:
movsb
loop INC_DIGIT_LOOP
mov cx, [ds:datalen]
inc cx
mov [ds:datalen], cx
mov al, '1'
mov [ds:buffer], al
jmp COUNT_INC_END

INC_DIGIT_2:
inc al
mov [ds:di], al

COUNT_INC_END:

MOVE_FILE_POINT:
mov ax, 4200H
xor cx, cx
xor dx, dx
mov bx, [ds:handle]
int 21H

FILE_DATA_WRITE:
mov ah, 40H
mov cx, [ds:datalen]
mov dx, buffer
mov bx, [ds:handle]
int 21H
jnc FILE_WRITE_OK
mov bx, ERRORTEXT3
call PRINT
jmp PROGRAM_END

FILE_WRITE_OK:

FILE_CLOSE:
mov ah, 3eH
mov bx, [ds:handle]
int 21H

COUNT_DATA:
mov bx, buffer
//--------------

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

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

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

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

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

guest

回答3

0

ラベルCOUNT_INCCOUNT_INC_END間は、「文字'0''9'の列からなる10進数に対して+1を計算する」処理になっています。(ように見えます。実動作チェックはしていませんので、バグの有無はご自身でご確認ください。)

例:"123"なら"124"に、"49"なら"50"に、"99"なら"100"に更新

各ラベル間で行われている処理の概要を書き下します。

COUNT_INC: ; 対象桁を一番右に設定 INC_DIGIT: ; もし全桁を走査済みならINC_DIGIT_1へ ; もし対象桁が文字'9'でなければ、INC_DIGIT_2へ ; 対象桁に文字'0'を代入 ; 対象桁をひとつ左にずらす ; INC_DIGITへもどる INC_DIGIT_1: ; 最初の桁数分の文字'0'を代入 ; 1桁増やして最左位置に文字'1'を代入 ; COUNT_INC_ENDへ INC_DIGIT_2: ; 対象桁の文字コードを+1する COUNT_INC_END:

投稿2015/03/03 09:51

編集2015/03/05 02:57
yohhoy

総合スコア6191

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

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

0

いまさらですけど、コメントを追加してみました。

COUNT_INC: mov si, buffer ; si : 読込んだデータ領域 mov di, buffer ; di : si += 読込んだデータのサイズ add di, [ds:datalen] INC_DIGIT: ; 繰上り走査処理 cmp si, di ; 走査終了判定 jz INC_DIGIT_1 ; 処理する文字は di でポイント ; データの後ろから前に向かって処理を進める dec di ; di を前方に移動する mov al, [ds:di] ; al ← 処理対象の文字 cmp al, '9' ; 対象文字が '9' 以外なら繰上り処理後に終了へ jnz INC_DIGIT_2 sub al, 9 ; 対象文字が '9' なら '0' に書換える mov [ds:di], al jmp INC_DIGIT ; 繰上り走査処理に戻る INC_DIGIT_1: ; 走査終了処理 mov cx, [ds:datalen] ; データの後ろ先頭まで走査したら ex)全部'9'な時 mov si, buffer ; 繰上がりの '1' の領域を確保するためにバッファ上で add si, cx ; データを一文字分右にずらすため mov di, si ; di : データの最終文字の次の位置 dec si ; si : データの最終文字の位置 std ; アドレス逆順転送設定 INC_DIGIT_LOOP: ; データの右シフト処理 movsb ; バイト転送 loop INC_DIGIT_LOOP ; cx(データサイズ)分ループ mov cx, [ds:datalen] ; 繰上り分のデータサイズを1増やす inc cx mov [ds:datalen], cx mov al, '1' ; 先頭に '1' を入れる mov [ds:buffer], al jmp COUNT_INC_END ; 終了へ INC_DIGIT_2: ; 繰上り加算 inc al mov [ds:di], al

基本は、与えられた文字列を後ろから走査して '9' なら '0' に書き換えて行き、'9' 以外のものが見つかったら、それに +1 して処理を終了するようです。

ex.)
”1234567890” → "1234567891"
"123456789" → "123456780" → "123456790"
"1234567899" → "1234567890" → "1234567800" → "1234567900"

ここで、走査が最後まで行ってしまった場合、つまり、すべての桁が '9' で全部 '0' に置き換えてしまった場合、データを右にシフトしてデータを拡張して先頭に1を埋め込み、データ長を増やしているようです。

ex.) "999" → "990" → "900" → "000" → "?000" → "1000"


それ以外の感想としては、

・ところどころの余計なセグメントオーバーライドプリフィクス(単に機械的につけているだけ?)
・mov al,'0' とせず sub al, 9 とする理由(この方が速いの?)
・途中脱出しない転送ループで rep movsb を使用せず、movsb + loop を使用する理由(割り込み応答配慮?)

この辺が、いまひとつ意味不明ですね。


すでに、時期を逸しているのは承知ですが、書き込みの練習にさせてもらいました。

投稿2015/11/07 21:42

T.Kanno

総合スコア915

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

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

0

私も勉強中です。
該当のコードは32bit向けです。
64bit / Linux 向けに書き換えてみました。
これで動作確認ができます。(gdbでレジスタとメモリの中身を見ながら実行するのがおすすめです)

ファイルのエラー処理はほとんど入っていないので、
必ず同一フォルダ内にcount.dat で数値を記載したファイルを準備してから実行してください。

INC_DIGITがループのメイン処理と言う事が理解できれば
少しはモヤモヤが晴れるかも。
頑張ってください。

lang

1;******************************************* 2; FILE: counter_sample.asm 3; 4; $nasm -f elf64 counter_sample.asm 5; $gcc -o counter_sample counter_sample.o 6; $./counter_sample 7; 8;******************************************* 9; Assembler Directives 10bits 64 ; target processor mode - 64bit 11 12; 13; *********** 14; count.dat : you have to create this file. it's write only '0'. 15; *********** 16; 0 17; 18 19 ; sysmte call 20 SYS_READ dq 00000001 ; read 21 SYS_WRITE dq 00000001 ; write 22 SYS_OPEN dq 00000002 ; open 23 SYS_CLOSE dq 00000003 ; close 24 SYS_CREAT dq 00000085 ; creat 25 SYS_BRK dq 00000012 ; brk 26 SYS_STAT dq 00000004 ; stat 27 28 ; file read parameter 29 O_RDONLY db 00000000 ; Read Only 30 O_WRONLY db 00000001 ; Write Only 31 O_RDWR dq 00000002 ; Read and Write 32 33 ; terminal 34 STDOUT dq 00000001 ; standard output 35 36 ; file path ./count.dat 37 FILENAME db 'count.dat', 00H 38 ERRORTEXT1 db 'ERROR OPEN', 00H 39 ERRORTEXT1_LEN equ $-ERRORTEXT1 40 ERRORTEXT2 db 'ERROR READ', 00H 41 ERRORTEXT2_LEN equ $-ERRORTEXT2 42 ERRORTEXT3 db 'ERROR WRITE', 00H 43 ERRORTEXT3_LEN equ $-ERRORTEXT3 44 45section .bss 46 buffer: resb 64 47 datalen: resw 1 48 handle: resw 1 49 50section .text 51 52 global main 53main: 54 55 ; FILE OPEN 56FILE_OPEN: 57 mov rax, [SYS_OPEN] ; system call OPEN 58 mov rdi, FILENAME ; file path address 59 mov rsi, [O_RDWR] ; READ and WRITE 60 syscall 61 62 ; Check File Open Result 63 mov r10, rax ; file discriptor to R10 64 cmp rax, 0x00000000 ; compare 65 jl c_MSG_ERROR ; rax < 0 then error 66 67FILE_DATA_READ: 68 mov rax, [SYS_READ] ; system call READ 69 mov rdi, r10 ; file discriptor 70 mov rsi, buffer ; read to memory 71 mov rdx, 63 ; length 72 syscall 73 74 75 ;jnc FILE_READ_OK 76 cmp rax, 0x00000000 ; compare 77 jl c_MSG_ERROR_READ ; goto Error Msg 78 79FILE_READ_OK: 80 mov r13, rax ; data length 81 sub r13, 1 ; 最後の制御文字分(1byte)を減らす 82 83COUNT_INC: ; 前準備 (数値が格納されている 先頭アドレスと 最終桁のアドレスを保存) 84 mov rsi, buffer ; 読み込み後の先頭アドレス 85 mov r14, r13 86 add r14, buffer ; 文字数(byte)+ 読み込み後の先頭アドレス 87 mov rdi, r14 ; 読み込み後の終了アドレス 88 89INC_DIGIT: ; 各桁の分岐処理 90 cmp rsi, rdi ; ファイルの先頭 と 処理中の桁アドレスを比較 91 jz INC_DIGIT_1 ; 桁上がり発生 92 dec rdi ; address を一つ減算 93 mov al, [rdi] ; 対象桁の値を取得 (2byte : ASCIIコード) 94 cmp al, '9' ; 9かどうかを比較 95 jnz INC_DIGIT_2 ; 9以外の場合にジャンプ 通常の桁上がり 96 mov al, '0' ; Ascii コード "0" 97 mov [rdi], al ; 処理中の桁を"0"に設定 98 jmp INC_DIGIT 99 100INC_DIGIT_1: ; 桁上がり発生(全ての桁が9である場合) 101 add r13, 1 ; 制御文字を加算 102 mov rcx, r13 ; 元々のデータ長 103 mov rsi, buffer ; データの格納されたアドレス 104 add rsi, rcx ; 桁数を加算 105 mov rdi, rsi ; 最終桁 106 dec rsi ; 1桁目(アドレスを一つ減らす) 107 std ; movsbを 108 109INC_DIGIT_LOOP: ;数値移動 110 movsb ; コピー rsi -> rdi 111 loop INC_DIGIT_LOOP ; データ長分ループ 112 mov rcx, r13 ; 元々のデータ長 113 inc rcx ; 一桁増やす 114 mov r13, rcx ; データ長に元々の桁数+1 115 mov al, '1' ; '1'を設定。 116 mov [buffer], al ; 最上位の桁に値を設定 117 jmp COUNT_INC_END ; 終了 118 119INC_DIGIT_2: ; 通常のカウントアップ 120 inc al ; inc al ; インクリメント (asciiコードでも大丈夫) 121 mov [rdi], al ; 対象の桁(アドレス)に値を設定 122 123COUNT_INC_END: 124 125MOVE_FILE_POINT: ; sys_write 用にファイルポインタを先頭に移動 126 127 mov rax, 8 ; system call lseek 128 mov rdi, r10 ; file discriptor 129 mov rsi, 0 ; offset (先頭) 130 mov rdx, 0 ; SEEK_SET 131 syscall 132 133FILE_DATA_WRITE: 134 mov rax, [SYS_WRITE] ; system call write 135 mov rdi, r10 ; file discriptor 136 mov rsi, buffer ; 数値データ 137 mov rdx, r13 ; LENGTH 138 syscall 139 140FILE_CLOSE: 141 mov rax, 3 ;sys_close 142 mov rdi, r10 ; file discriptor 143 syscall 144 145c_CONTENT_WRITE: 146 mov rax, [SYS_WRITE] 147 mov rsi, buffer ; value 148 mov rdx, r13 ; length 149 mov rdi, [STDOUT] ; terminal 150 syscall 151 152c_WRITE_LF: 153 ; print LF (= Line Feed) 154 mov rax, 0x0a ; LF 155 push rax 156 mov rdx, 02h ; char length 157 lea rsi, [rsp] ; [rsp] is stack pointer 158 mov rax, [SYS_WRITE] ; sys_write 159 mov rdi, [STDOUT] ; stdout 160 syscall 161 pop rax 162 163c_EXIT: 164 ;sys_exit(return_code) 165 mov rax, 60 ; sys_exit 166 mov rdi, 0 ; return 0 (success) 167 syscall ; if this is not, then 'segmentaition fault' 168 169c_MSG_ERROR: 170 ; FILE OPEN ERROR Message 171 mov rdx, ERRORTEXT1_LEN 172 mov rsi, ERRORTEXT1 173 mov rax, [SYS_WRITE] 174 mov rdi, [STDOUT] 175 syscall 176 jmp c_WRITE_LF ; write LF & exit 177 178c_MSG_ERROR_READ: 179 ; FILE READ ERROR Message 180 mov rdx, ERRORTEXT2_LEN 181 mov rsi, ERRORTEXT2 182 mov rax, [SYS_WRITE] 183 mov rdi, [STDOUT] 184 syscall 185 jmp c_WRITE_LF ; write LF & exit 186

投稿2015/05/28 12:36

simple-teq

総合スコア37

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

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

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

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問