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