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

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

ただいまの
回答率

90.48%

  • アルゴリズム

    420questions

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

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

受付中

回答 3

投稿

  • 評価
  • クリップ 1
  • VIEW 1,012

stack_hack

score 3

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
//--------------

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

+1

ラベル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:

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

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

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

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






;*******************************************
; FILE: counter_sample.asm
; 
; $nasm -f elf64 counter_sample.asm
; $gcc -o counter_sample counter_sample.o
; $./counter_sample
;  
;*******************************************
; Assembler Directives
bits 64       ; target processor mode - 64bit

;
; ***********
; count.dat : you have to create this file. it's write only '0'.
; ***********
; 0
;

    ; sysmte call    
    SYS_READ    dq    00000001    ; read
        SYS_WRITE    dq    00000001    ; write
        SYS_OPEN    dq    00000002    ; open
    SYS_CLOSE    dq    00000003    ; close
    SYS_CREAT    dq    00000085        ; creat
    SYS_BRK        dq    00000012    ; brk
    SYS_STAT    dq    00000004    ; stat

    ; file read parameter
    O_RDONLY    db    00000000    ; Read Only
    O_WRONLY    db    00000001    ; Write Only
    O_RDWR        dq    00000002    ; Read and Write

    ; terminal
    STDOUT        dq    00000001    ; standard output

    ; file path ./count.dat
    FILENAME    db 'count.dat', 00H  
    ERRORTEXT1    db 'ERROR OPEN', 00H 
    ERRORTEXT1_LEN    equ    $-ERRORTEXT1 
    ERRORTEXT2    db 'ERROR READ', 00H
    ERRORTEXT2_LEN    equ    $-ERRORTEXT2 
    ERRORTEXT3    db 'ERROR WRITE', 00H
    ERRORTEXT3_LEN    equ    $-ERRORTEXT3 

section .bss 
    buffer:     resb 64 
    datalen:     resw 1 
    handle:        resw 1  

section .text 
    
    global main
main:
    
    ; FILE OPEN
FILE_OPEN: 
    mov    rax,    [SYS_OPEN]    ; system call OPEN
    mov    rdi,    FILENAME    ; file path address
    mov    rsi,    [O_RDWR]    ; READ and WRITE
    syscall

    ; Check File Open Result
    mov    r10,    rax        ; file discriptor to R10
    cmp    rax,    0x00000000    ; compare
    jl    c_MSG_ERROR        ; rax < 0 then error

FILE_DATA_READ: 
    mov    rax,    [SYS_READ]    ; system call READ
    mov    rdi,    r10        ; file discriptor
    mov    rsi,    buffer        ; read to memory
    mov    rdx,    63        ; length 
    syscall
    
    
    ;jnc FILE_READ_OK 
    cmp    rax,    0x00000000    ; compare
    jl    c_MSG_ERROR_READ    ; goto Error Msg

FILE_READ_OK: 
    mov    r13,    rax        ; data length
    sub    r13,    1        ; 最後の制御文字分(1byte)を減らす

COUNT_INC:  ; 前準備 (数値が格納されている 先頭アドレスと 最終桁のアドレスを保存)
    mov    rsi, buffer        ; 読み込み後の先頭アドレス
    mov    r14, r13
    add    r14, buffer        ; 文字数(byte)+ 読み込み後の先頭アドレス
    mov    rdi, r14        ; 読み込み後の終了アドレス

INC_DIGIT:   ; 各桁の分岐処理 
    cmp    rsi, rdi        ; ファイルの先頭 と 処理中の桁アドレスを比較
    jz    INC_DIGIT_1        ; 桁上がり発生
    dec    rdi            ; address を一つ減算 
    mov    al,    [rdi]        ; 対象桁の値を取得 (2byte : ASCIIコード)
    cmp    al,    '9'        ; 9かどうかを比較 
    jnz    INC_DIGIT_2         ; 9以外の場合にジャンプ 通常の桁上がり
    mov    al,    '0'        ; Ascii コード "0"
    mov    [rdi],    al        ; 処理中の桁を"0"に設定 
    jmp INC_DIGIT 

INC_DIGIT_1:  ; 桁上がり発生(全ての桁が9である場合)
    add    r13,    1        ; 制御文字を加算
    mov    rcx,    r13        ; 元々のデータ長 
    mov    rsi,    buffer        ; データの格納されたアドレス
    add    rsi,    rcx        ; 桁数を加算
    mov    rdi,    rsi        ; 最終桁
    dec    rsi            ; 1桁目(アドレスを一つ減らす)
    std                 ; movsbを

INC_DIGIT_LOOP: ;数値移動 
    movsb                  ; コピー  rsi -> rdi
    loop    INC_DIGIT_LOOP        ; データ長分ループ
    mov    rcx,    r13        ; 元々のデータ長
    inc    rcx            ; 一桁増やす
    mov    r13,    rcx        ; データ長に元々の桁数+1
    mov    al,     '1'        ; '1'を設定。
    mov    [buffer], al        ; 最上位の桁に値を設定
    jmp COUNT_INC_END        ; 終了

INC_DIGIT_2:   ; 通常のカウントアップ
    inc    al            ; inc al ; インクリメント (asciiコードでも大丈夫)
    mov    [rdi],    al        ; 対象の桁(アドレス)に値を設定

COUNT_INC_END: 

MOVE_FILE_POINT: ; sys_write 用にファイルポインタを先頭に移動
    
    mov    rax,    8        ; system call lseek
    mov    rdi,    r10        ; file discriptor
    mov    rsi,    0        ; offset (先頭)
    mov    rdx,    0        ; SEEK_SET
    syscall

FILE_DATA_WRITE: 
    mov    rax,    [SYS_WRITE]    ; system call write
    mov    rdi,    r10        ; file discriptor
    mov    rsi,    buffer        ; 数値データ
    mov    rdx,    r13        ; LENGTH
    syscall    

FILE_CLOSE: 
    mov    rax,    3        ;sys_close
    mov    rdi,    r10        ; file discriptor
    syscall

c_CONTENT_WRITE:
    mov    rax,    [SYS_WRITE]
    mov    rsi,    buffer        ; value
    mov    rdx,    r13        ; length
    mov    rdi,    [STDOUT]    ; terminal
    syscall

c_WRITE_LF:
    ; print LF (= Line Feed)
    mov    rax,    0x0a        ; LF
    push    rax
    mov    rdx,    02h        ; char length
    lea    rsi,    [rsp]        ; [rsp] is stack pointer
    mov    rax, [SYS_WRITE]    ; sys_write
    mov    rdi, [STDOUT]        ; stdout
    syscall
    pop    rax

c_EXIT:
    ;sys_exit(return_code)
    mov    rax,    60    ; sys_exit
    mov    rdi,    0    ; return 0 (success)
    syscall            ; if this is not, then 'segmentaition fault'

c_MSG_ERROR:
    ; FILE OPEN ERROR Message
    mov    rdx, ERRORTEXT1_LEN
    mov    rsi, ERRORTEXT1
    mov    rax, [SYS_WRITE]
    mov    rdi, [STDOUT]
    syscall
    jmp    c_WRITE_LF    ; write LF & exit

c_MSG_ERROR_READ:
    ; FILE READ ERROR Message
    mov    rdx, ERRORTEXT2_LEN
    mov    rsi, ERRORTEXT2
    mov    rax, [SYS_WRITE]
    mov    rdi, [STDOUT]
    syscall
    jmp    c_WRITE_LF    ; write LF & exit

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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 を使用する理由(割り込み応答配慮?)

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


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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

関連した質問

  • 解決済

    wavファイルの波形表示

    wavファイルの勉強がてら、プログラムを書いています。 wavファイルを読み込んで波形を表示したいのですが、どうも速度が遅すぎます。 約30秒ほどのwavファイルが、1~2分かか

  • 解決済

    カンマ区切りのデータの重複する要素とその値を合計したい

    閲覧ありがとうございます。 カンマ区切りのデータの重複する要素とその値を合計したいのですが、どのようにすればよいのでしょうか? とても大きなデータなので、excelでは開け

  • 解決済

    大量のベクトルデータをCSVファイルに出力したら、途中のデータが省略されてしまう

    CountVectorizerで単語の出現数をカウントしたデータをCSVファイルに出力したところ、 途中のデータが省略されてしまいます。(printも同様) 全データを出力する

  • 解決済

    nasm システムコールの疑問

    自分はnasm 16bit のプログラミングを勉強したものです 今はnasm 32bitをubuntuの端末で動かそうとしているのですが nasm16bitではシステムコールがin

  • 解決済

    ただファイルを開くだけのプログラム

    Ubuntuの端末で動くアセンブリ言語のただファイルを開くだけのシステムを作ってみましたが実行コアダンプが発生します。 具体的には開くだけのシステム+開けたかどうか表示をするプログ

  • 解決済

    対処方法:a bytes-like object is required, not 'str'

     前提・実現したいこと python初心者です。 float型の配列を1件ずつ読み込み、byteに変換したのですが、当該エラーが発生してしまいます。 [float(x)]としても何

  • 解決済

    C⇒pythonへのコンバート方法

     前提・実現したいこと Pyhton初心者です。 該当ソースは、C言語で作成されているのですが、pythonへコンバートした際の記述が不明な為、ご教授をお願いいたします。 主に「f

  • 解決済

    サブルーチンの中身をアセンブリ言語で見てみたいです。

    callされるサブルーチン自体をアセンブリプログラムで出力する方法はないでしょうか? やはり、サブルーチンのアセンブリプログラムを見るにはサブルーチンのみを別のプログラムとして

同じタグがついた質問を見る

  • アルゴリズム

    420questions

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