Сложить два аргумента командной строки nasm

Тема в разделе "WASM.BEGINNERS", создана пользователем dcc0, 10 июл 2023.

  1. dcc0

    dcc0 Member

    Публикаций:
    2
    Регистрация:
    22 дек 2022
    Сообщения:
    60
    Думал-думал, рыл Интернет, но так и не нашёл решения.
    Суть задачи: сделать что-то вроде калькулятора; два аргумента командной строки склдываются и выводятся.
    Ассемблер nasm. синтаксис Intel.

    Пока получилось только вывести аргумент:
    Код (ASM):
    1. ; Вывод аргумента
    2. ; Команда запуска
    3. ; nasm -f elf32 1.asm; ld -m elf_i386 -s -o 1 1.o; ./1 8 3
    4. section .text
    5. global _start             ;must be declared for using gcc
    6. _start:                     ;tell linker entry point
    7. push ebp                ; работа со стеком
    8. mov  ebp, esp
    9.         mov  eax, ebp[12]    ;читаем адрес стека, в котором хранится первый аргумент
    10.         mov [string], eax ;пишеи его в строку
    11.                 mov ecx, string[0]   ; пишем строку для вывода
    12.                 mov     edx, 2       ;длина  выводимой строки
    13.                 mov     ebx, 1        ;file descriptor (stdout)
    14.                 mov     eax, 4        ;system call number (sys_write)
    15.                 int     0x80            ;call kernel
    16.                 mov     eax, 1        ;system call number (sys_exit)
    17.                 int     0x80            ;call kernel
    18. section .data
    19.         string db 4; строка в 4 байта
    Первый аргумент берётся из стека по адресу ebp[12].
    Как я понимаю, это адрес начала строки, то есть в string[0] попадает адрес кадра (если я не ошибаюсь).
    Символ, указанный в качестве аргумента, получается вести, если ограничить длину строки, но оперировать с ним не получается. А хотелось бы дотянуться до него так, чтобы, допустим, прибавить к нему число. Задача практической ценности не имеет (просто что-то вроде головоломки).
     
  2. q2e74

    q2e74 Active Member

    Публикаций:
    0
    Регистрация:
    18 окт 2018
    Сообщения:
    999
    dcc0 нравится это.
  3. dcc0

    dcc0 Member

    Публикаций:
    2
    Регистрация:
    22 дек 2022
    Сообщения:
    60
    Благодарю.
    --- Сообщение объединено, 10 июл 2023 ---
    Окызвается, всё непросто.
     
  4. dcc0

    dcc0 Member

    Публикаций:
    2
    Регистрация:
    22 дек 2022
    Сообщения:
    60
    Вроде бы понял. Но я, правда, так сложно не планировал делать. Я проще хотел , чтобы разобраться. Вроде бы получилось, просто сложить два аргумента. Непонятно было именно, как обратиться к символу строки из стека.
    А там, по ссылке, ещё объясняется, как определить, что символ строки конвертируется или не конвертируется в число. Но без объяснения, которое там есть на английском, сам код кажется слишком сложным.
    Код (ASM):
    1. ;Простейший калькулятор для сложения двух чисел, взятых из аргументов
    2. ;Команда запуска
    3. ;nasm -f elf32 1.asm; ld -m elf_i386 -s -o 1 1.o; ./1 1 2
    4. section .text
    5. global _start             ;must be declared for using gcc
    6. _start:                     ;tell linker entry point
    7. push ebp                ; Работа со стеком
    8. mov ebp, esp
    9. push    esi             ; Кладём esi на стек
    10.  mov esi, esp[12]    ; Вынимаем из стека строку с аргуметом и кладём в esi
    11.    mov ecx, 4          ; Для первого аргумента - символа
    12.    mov bl, [esi+ecx] ; Кладём в ebx, именно в bl, содержимое стека со смещением  до символа 4
    13.    sub bl, '0'            ; Вычитаем из bl 0
    14.    mov ecx, 6          ; Кладём второй аргумент
    15.    add bl, [esi+ecx]  ; Складываем
    16.     mov     [sum], ebx ;Кладём результат в sum
    17.     mov     ecx, sum   ; Кладём sum в ecx для вывода
    18.     mov     edx, 2
    19.     mov     ebx, 1          ;file descriptor (stdout)
    20.     mov     eax, 4          ;system call number (sys_write)
    21.     int     0x80               ;call kernel
    22.     mov     eax, 1          ;system call number (sys_exit)
    23.     int     0x80               ;call kernel
    24. section .data
    25.   sum db 4;
     
  5. dcc0

    dcc0 Member

    Публикаций:
    2
    Регистрация:
    22 дек 2022
    Сообщения:
    60
    Разобрался всё-таки с 16 уроком. Чтобы понять отредактировал тот код и поудалял многое.
    Оказывается, я в общем верно мыслил, но упорно пытался класть символ в al, а не в bl.
    Незнание внутренней механики сказывается. С использованием гадательного метода, пожалуй, больше не буду программировать, :) но всё же увлекательные два дня были.
    Ассемблер, оказывается, довольно выразителен, даже при беглом знакомстве. Спасибо за помощь! Будто шахматную задачу решил.
    Код (ASM):
    1. ;Данный скрипт является только примером для изучения
    2. ;Команда запуска
    3. ;nasm -f elf32 7.asm; ld -m elf_i386 -s -o 7 7.o; ./7 123
    4.  
    5. section .text
    6. global _start             ;must be declared for using gcc
    7. _start:
    8.  
    9.     pop  ecx             ; first value on the stack is the number of arguments
    10.     pop edx             ; second value on the stack is the program name (discarded when we initialise edx)
    11.     pop eax             ; Здесь будет результат
    12.  
    13.     mov     esi, eax        ; move pointer in eax into esi (our number to convert)
    14.     mov     eax, 0          ; initialise eax with decimal value 0
    15.     mov     ecx, 0          ; Счётчик цикла
    16. lp3:
    17.     xor     ebx, ebx         ; Обнулим ebx
    18.     mov     bl, [esi+ecx]  ; Запишем в bl новое значение из строки. Пишем именно в bl
    19.     sub     bl, 48            ; convert ebx register's lower half to decimal representation of ascii value
    20.     add     eax, ebx        ; add ebx to our interger value in eax
    21.     mov     ebx, 10         ; move decimal value 10 into ebx. Умножим на 10
    22.     mul     ebx              ; Само умножение
    23.      inc     ecx               ; Инкремент
    24.      cmp ecx, 3             ; Условие выхода
    25. jne lp3
    26.  
    27.                                    ; Делим eax на 10 в конце, чтобы удалить лишний разряд
    28.     mov     ebx, 10         ; move decimal value 10 into ebx
    29.     div     ebx
    30.                                 ; Вывод через деление
    31. mov edi, 6                  ; Счётчик
    32. loop:                           ;Начало цикла
    33.         dec edi                ;Декремент, чтобы  записать все значения остатка в stroka
    34.         mov ebx, 10         ;Делитель. Запишем  в цикл, чтобы вернуть ему значение на новой итерации
    35.         xor edx, edx         ;Обнулим остаток
    36.         div ebx                ;Делим (edx,eax)/ebx = eax, edx
    37.         add edx, 30h             ;Добавим в остаток 0, равносильно add edx, '0'
    38.         mov  [result + edi], dl  ;Пишем в строку остаток в обратном порядке.
    39.         cmp edi,  0                 ;Выходим
    40. jne loop
    41.  
    42.     mov     ecx, result  ;пишем для вывода
    43.     mov     edx, 6        ;длина строки
    44.     mov     ebx, 1       ;file descriptor (stdout)
    45.     mov     eax, 4       ;system call number (sys_write)
    46.     int     0x80            ;call kernel
    47.  
    48.     mov     eax, 1        ;system call number (sys_exit)
    49.     int     0x80
    50. section .data
    51.           result db   6, 13, 10, 0 ;массив для вывода