0

我正在读一本书(Assembly Language Step by Step,Programming with Linux by Jeff Duntemann),我正在尝试更改这个显示参数的程序,以显示环境变量。我试图只使用到目前为止所教的内容(没有 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!

我将位移向上移动到 和 中的第一个空指针到第一个环境变量([ebp+4+ebx*4] > [ebp+16+ebx*4])。当我与我拥有的环境变量的数量(44)进行比较时,它会在没有段错误的情况下很好地打印它们,与 45 相比只会给我一个段错误。ScanOneShowem

我尝试使用指针与零进行比较(搜索空指针):cmp dword [ebp+16+ebx*4],0h但这只是返回一个段错误。我确信空指针出现在堆栈中的最后一个环境变量之后,但它就像它不会做任何事情一样。

我哪里错了?

4

2 回答 2

0

如果你的程序有 2、3 或 0 个参数,你的代码还能工作吗?每个部分由一个 NULL 指针(0 的 4 个字节)分隔您可以只获取参数的计数并将其用作数组索引并跳过 args 直到到达 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 回答