Нахождение нулевого указателя после переменных среды

Я читаю книгу (пошаговый язык ассемблера, программирование под 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!

Я переместил смещение выше первого нулевого указателя на первую переменную окружения ([ebp+4+ebx*4] > [ebp+16+ebx*4]) в обоих ScanOne а также Showem, Когда я сравниваю с количеством переменных окружения, которые у меня есть (44), он будет печатать их без ошибок, тогда как сравнение с 45 дает мне только ошибку.

Я попытался использовать указатели для сравнения с нулем (в поисках нулевого указателя): cmp dword [ebp+16+ebx*4],0h но это просто возвращает сегфо Я уверен, что нулевой указатель идет после последней переменной окружения в стеке, но похоже, что он не будет ничего делать до и после этого.

Куда я иду не так?

2 ответа

Решение

Что если ваша программа имеет 2, 3 или 0 аргументов, будет ли ваш код работать? Каждый раздел разделен указателем NULL (4 байта по 0). Вы можете просто получить количество параметров и использовать их в качестве индекса массива и пропускать аргументы, пока не доберетесь до байтов 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 здесь, но вы просто меняете это местным системным вызовом.

Хочу пойти дальше и извиниться, это всегда случается со мной (исправьте это самостоятельно, задав вопрос о stackru). Я думаю, что когда я попытался сравнить указатель с 0h, я набрал что-то неправильно. Вот что я сделал:

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

а также

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

Это сработало.

Другие вопросы по тегам