1

x86アセンブリを学習しようとしています。私が使っている本はAssembly Language - Step by Step, Programming With Linux(かなり良いと言わざるを得ない)です。私はこれまで多くのことを学んできましたが、多くの点で先を行くように自分自身に挑戦する必要があると感じています。そうすることで、より早く学ぶことができます (フォローアロング、トップダウンの学習を行うことはできますが、退屈だと思います)スロー)。

そこで、2 つのレジスタ (32 ビット) を乗算してから、データをコンソールに出力するのは素晴らしいアイデアだと思いました。

問題は、プログラムを実行すると (本と同じように NASM を使用していますが、Insight デバッガーは使用していません)、セグメンテーション エラーが発生することです。私はこの小さなハンマーでgdbでかなりの量のデバッグを行いましたが、何らかの理由で問題が何であるかを理解できないようです。

セグメンテーション違反が発生する理由と、問題を叱責する良い方法を教えてください。また、コードで行ったコメントが実際に起こっていることと一致しない場合は、誰かがそれを修正してくれれば幸いです。

これまでの私のコードは次のとおりです(よくコメントされています)

ありがとう。

コードズ

section .data
;TODO

section .bss
valueToPrint: resb 4            ;alloc 4 bytes of data in 'valueToPrint'

section .text

global _start

_mul:
    mov eax, 0x2A ;store 42 in eax
    mov edx, 0x2A ;store 42 in edx
    mul eax
    ret

_safe_exit:
    mov eax, 1  ;initiate 'exit' syscall
    mov ebx, 0  ;exit with error code 0
    int 0x80    ;invoke kernel to do its bidding 

_start:
    nop                         ;used to keep gdb from complaining

    call _mul                       ;multiply the values
    mov [valueToPrint], eax         ;store address of eax in the contents of valueToPrint
    mov eax, 4                      ;specify a system write call - aka syswrite
    mov ebx, 1                      ;direction used to make the syswrite call output to console - i.e. stdout
    mov dword [ecx], valueToPrint   ;store valueToPrint in ecx: ecx represents the syswrite register
    int 0x80                        ;invoke kernel based on the given parameters

    call _safe_exit

編集

また、それが違いを生む場合、私は Arch Linux を実行しています。

4

2 に答える 2

3

この行がセグメンテーション違反の原因です:

mov dword [ecx], valueToPrint

valueToPrintaddress のメモリ位置に格納するように指示していますecx。初期化することはありませんecx(カーネルはおそらくプログラムの開始時に0に初期化します)。そのため、逆参照すると、無効なメモリ位置にアクセスすることになります。

write(2)システム コールは 3 つのパラメータを取ります。レジスタ内のファイル記述子番号、書き込むebx文字列へのポインタecx、および書き込むバイト数ですedx。したがって、結果の生のバイナリ データを出力するだけの場合は、 のアドレスを渡し、valueToPrintそのアドレスから 4 バイトを出力するように指示できます。この場合、valueToPrintは 1764 (16 進数で 0x6e4) であるため、このコードはe4 06 00 00x86 で 4 バイトを出力します。これはリトル エンディアンです。

mov [valueToPrint], eax   ; store the result into memory
mov eax, 4                ; system call #4 = sys_write
mov ebx, 1                ; file descriptor 1 = stdout
mov ecx, valueToPrint     ; store *address* of valueToPrint into ecx
mov edx, 4                ; write out 4 bytes of data
int 0x80                  ; syscall
于 2012-06-29T05:10:39.763 に答える
1

編集してください!(cmpを忘れました!)

基数 10 で値を出力するには...

; assuming value is in EAX (only)
.loop1:
    div   10      ; divide by 10, leave result in eax, REMAINDER in edx
    push  eax     ; save value
    mov   eax,edx
    or    eax,0x30 ; convert 0-9 to '0'-'9' (ascii 0x30='0')
    call  display_a_char ; (you write this!)
    pop   eax
    or    eax,eax ; set flags (edit!)
    jnz   .loop1
; all done, maybe put a \n return or something here
于 2012-06-29T05:32:49.963 に答える