Как получить аргументы из командной строки (сборка nasm ubuntu 32bit)? - PullRequest
0 голосов
/ 30 ноября 2018

Я хочу «напечатать» аргумент в командной строке, например, когда я набираю «$. / Sum3 10» (в командной строке), в следующей строке должно быть показано число «10»

(вот так)

$. / sum3 10
10

и это код.

            segment .bss
     p_arv  resd 1
            segment .text
            global main
     main:
            enter 0,0
            pusha

            mov eax, dword [ebp+12] ; move pointer to argv to eax
            mov [p_argv], eax

            mov eax, [p_argv + 4] ; move number '10' to eax
            call print_int
            call print_nl

            popa
            mov eax, 0
            leave 
            ret

Я ожидал, что стек будет

-------------------------- вершина стека
10 (argv [1], [p_argv + 4])
./sum3 (argv [0], [p_argv])

...

указатель на argv (EBP + 12)
количество аргументов (EBP + 8)
адрес возвратаосновной
EBP

----------------------- нижний стек

Но,

результат

$. / sum3 10
0

Я не могу понять, почему отображается «0».так как я могу получить правильный номер (аргумент)?

1 Ответ

0 голосов
/ 30 ноября 2018

Пример выглядит как C-функция с "ассемблерным кодом", например, компилятор C добавляет некоторый стартовый код и вызывает его как функцию.В этом стартовом коде командная строка Linux обрабатывается до параметров C, которые выглядят как

int main(int argc, char *argv[]) resp. int main(int argc, char **argv)

В стеке вы получаете только два аргумента: число (argc) и указатель на списокуказатели на строку.Вы должны разыменовать эти указатели.

Взгляните на этот пример:

; Name:     get_argv_gcc.asm
; Assemble: nasm -felf32 get_argv_gcc.asm
; Link:     gcc -m32 -oget_argv_gcc get_argv_gcc.o
; Run:      ./get_argv_gcc arg1 arg2 arg3

SECTION  .data
    argcstr     db `argc = %d\n\0`      ; backquotes for C-escapes
    argvstr     db `argv[%u] = %s\n\0`

SECTION .text
global  main
extern printf
main:

    push ebp                    ; Prolog
    mov ebp, esp
    push ebx                    ; Callee saved registers
    push esi

    mov eax, [ebp + 8]          ; argc
    push eax
    push argcstr
    call printf                 ; Call libc
    add esp, (2*4)              ; Adjust stack by 2 arguments

    mov esi, [ebp + 12]         ; **argv
    mov ebx, 0                  ; Index of argv
    .J1:
    mov eax, [esi + ebx * 4]    ; *argv[ebx]
    test eax, eax               ; Null pointer?
    je .J2                      ; Yes -> end of loop
    push eax                    ; Pointer to string
    push ebx                    ; Integer
    push argvstr                ; Pointer to format string
    call printf                 ; Call libc
    add esp, (3*4)              ; Adjust stack by 3 arguments
    inc ebx
    jmp .J1                     ; Loop
    .J2:

    xor eax, eax                ; Returncode = return(0)
    pop esi                     ; Epilog
    pop ebx
    leave
    ret

Чистая программа сборки, которая вызывается оболочкой, получает аргументы, немного отличающиеся в стеке.Об этом есть отличная статья: NASM - Linux Получение параметров командной строки .Попробуйте мой пример:

; Name:     get_argv.asm
; Assemble: nasm -felf32 get_argv.asm
; Link:     ld -m elf_i386 -o get_argv get_argv.o
; Run:      ./get_argv arg1 arg2 arg3

SECTION  .data
    LineFeed    dw  10
    nullstr     db '(null)',0
    argcstr     db 'argc = '
    argcstr1    db '---------------',0
    argvstr     db 'argv['
    argvstr1    db '---------------',0
    argvstr2    db '] = ',0

SECTION .text
global  _start
_start:

    push    ebp
    mov     ebp, esp

    mov eax, [ebp + 4]          ; argc
    mov edi, argcstr1
    call EAX_to_DEC             ; Convert EAX to a string pointed by EDI

    mov esi, argcstr
    call PrintString
    mov esi, LineFeed
    call PrintString

    xor ecx, ecx

    .J1:
    mov eax, ecx
    mov edi, argvstr1
    call EAX_to_DEC             ; Convert EAX to a string pointed by EDI

    mov esi, argvstr
    call PrintString
    mov esi, argvstr2
    call PrintString
    mov esi, [ebp+8+4*ecx]      ; argv[ECX]
    call PrintString
    test esi, esi
    jz .J2
    mov esi, LineFeed
    call PrintString
    add ecx, 1
    jmp .J1
    .J2:

    .exit:
    mov esi, LineFeed
    call PrintString

    mov     esp, ebp
    pop     ebp

    mov     eax, 1              ; SYS_EXIT
    xor     ebx, ebx            ; Exit code = 0 = no error
    int     0x80                ; Call Linux

PrintString:                    ; ARG: ESI Pointer to ASCIZ string
    pusha
    test esi, esi
    jne .J0
    mov esi, nullstr
    .J0:
    mov eax, 4                  ; SYS_WRITE
    mov ebx, 1                  ; STDOUT
    mov ecx, esi
    xor edx, edx                ; Count of bytes to send
    .J1:
    cmp byte [esi], 0           ; Look for the terminating null
    je .J2
    add edx, 1
    add esi, 1
    jmp .J1
    .J2:
    int 0x80                    ; Call Linux
    popa
    ret

EAX_to_DEC:                     ; ARG: EAX integer, EDI pointer to string buffer
    push ebx
    push ecx
    push edx

    mov ebx, 10                 ; Divisor = 10
    xor ecx, ecx                ; ECX=0 (digit counter)
    .J1:                        ; First Loop: store the remainders
    xor edx, edx                ; Don't forget it!
    div ebx                     ; EDX:EAX / EBX = EAX remainder EDX
    push dx                     ; Push the digit in DL (LIFO)
    add cl, 1                   ; = inc cl (digit counter)
    or eax, eax                 ; AX == 0?
    jnz .J1                     ; No: once more
    mov ebx, ecx                ; Store count of digits
    .J2:                        ; Second loop: load the remainders in reversed order
    pop ax                      ; get back pushed digits
    or al, 00110000b            ; to ASCII
    mov [edi], al               ; Store AL to [EDI] (EDI is a pointer to a buffer)
    add edi, 1                  ; = inc edi
    loop .J2                    ; until there are no digits left
    mov byte [edi], 0           ; ASCIIZ terminator (0)
    mov eax, ebx                ; Restore Count of digits

    pop edx
    pop ecx
    pop ebx
    ret                         ; RET: EAX length of string (w/o last null)
...