0

私は本を​​読んでいます (アセンブリ言語のステップ バイ ステップ、 Jeff Duntemann による Linux でのプログラミング) で、引数を表示するこのプログラムを変更して、代わりに環境変数を表示しようとしています。私はこれまでに教えられたもの(Cなし)のみを使用しようとしています。プログラムに環境変数を出力させましたが、持っている数を数えて即時を使用した後でのみ、明らかに満足のいくものではありませんでした。ここに私が持っているものがあります:

global  _start          ; Linker needs this to find the entry point!

_start:
    nop         ; This no-op keeps gdb happy...

    mov ebp,esp     ; Save the initial stack pointer in EBP
; Copy the command line argument count from the stack and validate it:
    cmp dword [ebp],MAXARGS ; See if the arg count exceeds MAXARGS
    ja Error        ; If so, exit with an error message

; Here we calculate argument lengths and store lengths in table ArgLens:
    xor eax,eax     ; Searching for 0, so clear AL to 0
    xor ebx,ebx     ; Stack address offset starts at 0
ScanOne:
    mov ecx,0000ffffh   ; Limit search to 65535 bytes max
    mov edi,dword [ebp+16+ebx*4] ; Put address of string to search in EDI
    mov edx,edi     ; Copy starting address into EDX                                                                                                                                                                                                                                                                                                         
    cld         ; Set search direction to up-memory
    repne scasb     ; Search for null (0 char) in string at edi
    jnz Error       ; REPNE SCASB ended without finding AL
    mov byte [edi-1],10 ; Store an EOL where the null used to be
    sub edi,edx     ; Subtract position of 0 from start address
    mov dword [ArgLens+ebx*4],edi   ; Put length of arg into table
    inc ebx         ; Add 1 to argument counter
    cmp ebx,44; See if arg counter exceeds argument count
    jb ScanOne      ; If not, loop back and do another one

; Display all arguments to stdout:
    xor esi,esi     ; Start (for table addressing reasons) at 0
Showem:
    mov ecx,[ebp+16+esi*4]  ; Pass offset of the message
    mov eax,4       ; Specify sys_write call
    mov ebx,1       ; Specify File Descriptor 1: Standard Output
    mov edx,[ArgLens+esi*4] ; Pass the length of the message
    int 80H         ; Make kernel call
    inc esi         ; Increment the argument counter
    cmp esi,44  ; See if we've displayed all the arguments
    jb Showem       ; If not, loop back and do another
    jmp Exit        ; We're done! Let's pack it in!

と の両方で、変位を最初の null ポインターを超えて最初の環境変数 ( [ebp+4+ebx*4] > [ebp+16+ebx*4]) に移動しました。私が持っている環境変数の数(44)と比較すると、セグメンテーション違反なしで問題なく出力されます.45と比較すると、セグメンテーション違反のみが発生します。ScanOneShowem

ポインターを使用してゼロと比較しようとしました(nullポインターを検索して):cmp dword [ebp+16+ebx*4],0hしかし、それはセグメンテーション違反を返すだけです。スタック内の最後の環境変数の後にヌルポインターが来ると確信していますが、それ以上は何もしないようです。

どこが間違っていますか?

4

2 に答える 2

0

プログラムの引数が 2 つ、3 つ、または 0 の場合でも、コードは機能しますか? 各セクションは NULL ポインター (0 の 4 バイト) で区切られています。パラメーターの数を取得し、それを配列インデックスとして使用して、NULL バイトに到達するまで引数をスキップすることができます。これで、環境ブロックができました。

ここに画像の説明を入力

extern printf, exit

section .data
fmtstr      db  "%s", 10, 0
fmtint      db  "%d", 10, 0

global main

section .text
main:
    push    ebp
    mov     ebp, esp

    mov     ebx, [ebp + 4]

.SkipArgs:  
    mov     edi, dword [ebp + 4 * ebx]
    inc     ebx
    test    edi, edi
    jnz     .SkipArgs

.ShowEnvBlock:
    mov     edi, dword [ebp + 4 * ebx]
    test    edi, edi
    jz      .NoMore

    push    edi
    push    fmtstr
    call    printf
    add     esp, 4 * 2
    inc     ebx
    jmp     .ShowEnvBlock

.NoMore:    
    push    0
    call    exit

はいprintf、ここで使用しますが、それをシステムコールと交換するだけです。

于 2013-11-14T04:59:02.673 に答える
0

先に進んで謝罪したいのですが、これは常に私に起こります(stackoverflowで質問した後、自分で修正してください)。ポインターを 0h と比較しようとしたときに、何か間違ったことを入力したと思います。これが私がしたことです:

inc ebx
cmp dword [ebp+16+ebx*4],0h
jnz ScanOne

inc esi
cmp dword [ebp+16+esi*4],0h
jnz Showem

これはうまくいきました。

于 2013-11-13T20:54:07.183 に答える