Думал-думал, рыл Интернет, но так и не нашёл решения. Суть задачи: сделать что-то вроде калькулятора; два аргумента командной строки склдываются и выводятся. Ассемблер nasm. синтаксис Intel. Пока получилось только вывести аргумент: Код (ASM): ; Вывод аргумента ; Команда запуска ; nasm -f elf32 1.asm; ld -m elf_i386 -s -o 1 1.o; ./1 8 3 section .text global _start ;must be declared for using gcc _start: ;tell linker entry point push ebp ; работа со стеком mov ebp, esp mov eax, ebp[12] ;читаем адрес стека, в котором хранится первый аргумент mov [string], eax ;пишеи его в строку mov ecx, string[0] ; пишем строку для вывода mov edx, 2 ;длина выводимой строки mov ebx, 1 ;file descriptor (stdout) mov eax, 4 ;system call number (sys_write) int 0x80 ;call kernel mov eax, 1 ;system call number (sys_exit) int 0x80 ;call kernel section .data string db 4; строка в 4 байта Первый аргумент берётся из стека по адресу ebp[12]. Как я понимаю, это адрес начала строки, то есть в string[0] попадает адрес кадра (если я не ошибаюсь). Символ, указанный в качестве аргумента, получается вести, если ограничить длину строки, но оперировать с ним не получается. А хотелось бы дотянуться до него так, чтобы, допустим, прибавить к нему число. Задача практической ценности не имеет (просто что-то вроде головоломки).
Вроде бы понял. Но я, правда, так сложно не планировал делать. Я проще хотел , чтобы разобраться. Вроде бы получилось, просто сложить два аргумента. Непонятно было именно, как обратиться к символу строки из стека. А там, по ссылке, ещё объясняется, как определить, что символ строки конвертируется или не конвертируется в число. Но без объяснения, которое там есть на английском, сам код кажется слишком сложным. Код (ASM): ;Простейший калькулятор для сложения двух чисел, взятых из аргументов ;Команда запуска ;nasm -f elf32 1.asm; ld -m elf_i386 -s -o 1 1.o; ./1 1 2 section .text global _start ;must be declared for using gcc _start: ;tell linker entry point push ebp ; Работа со стеком mov ebp, esp push esi ; Кладём esi на стек mov esi, esp[12] ; Вынимаем из стека строку с аргуметом и кладём в esi mov ecx, 4 ; Для первого аргумента - символа mov bl, [esi+ecx] ; Кладём в ebx, именно в bl, содержимое стека со смещением до символа 4 sub bl, '0' ; Вычитаем из bl 0 mov ecx, 6 ; Кладём второй аргумент add bl, [esi+ecx] ; Складываем mov [sum], ebx ;Кладём результат в sum mov ecx, sum ; Кладём sum в ecx для вывода mov edx, 2 mov ebx, 1 ;file descriptor (stdout) mov eax, 4 ;system call number (sys_write) int 0x80 ;call kernel mov eax, 1 ;system call number (sys_exit) int 0x80 ;call kernel section .data sum db 4;
Разобрался всё-таки с 16 уроком. Чтобы понять отредактировал тот код и поудалял многое. Оказывается, я в общем верно мыслил, но упорно пытался класть символ в al, а не в bl. Незнание внутренней механики сказывается. С использованием гадательного метода, пожалуй, больше не буду программировать, но всё же увлекательные два дня были. Ассемблер, оказывается, довольно выразителен, даже при беглом знакомстве. Спасибо за помощь! Будто шахматную задачу решил. Код (ASM): ;Данный скрипт является только примером для изучения ;Команда запуска ;nasm -f elf32 7.asm; ld -m elf_i386 -s -o 7 7.o; ./7 123 section .text global _start ;must be declared for using gcc _start: pop ecx ; first value on the stack is the number of arguments pop edx ; second value on the stack is the program name (discarded when we initialise edx) pop eax ; Здесь будет результат mov esi, eax ; move pointer in eax into esi (our number to convert) mov eax, 0 ; initialise eax with decimal value 0 mov ecx, 0 ; Счётчик цикла lp3: xor ebx, ebx ; Обнулим ebx mov bl, [esi+ecx] ; Запишем в bl новое значение из строки. Пишем именно в bl sub bl, 48 ; convert ebx register's lower half to decimal representation of ascii value add eax, ebx ; add ebx to our interger value in eax mov ebx, 10 ; move decimal value 10 into ebx. Умножим на 10 mul ebx ; Само умножение inc ecx ; Инкремент cmp ecx, 3 ; Условие выхода jne lp3 ; Делим eax на 10 в конце, чтобы удалить лишний разряд mov ebx, 10 ; move decimal value 10 into ebx div ebx ; Вывод через деление mov edi, 6 ; Счётчик loop: ;Начало цикла dec edi ;Декремент, чтобы записать все значения остатка в stroka mov ebx, 10 ;Делитель. Запишем в цикл, чтобы вернуть ему значение на новой итерации xor edx, edx ;Обнулим остаток div ebx ;Делим (edx,eax)/ebx = eax, edx add edx, 30h ;Добавим в остаток 0, равносильно add edx, '0' mov [result + edi], dl ;Пишем в строку остаток в обратном порядке. cmp edi, 0 ;Выходим jne loop mov ecx, result ;пишем для вывода mov edx, 6 ;длина строки mov ebx, 1 ;file descriptor (stdout) mov eax, 4 ;system call number (sys_write) int 0x80 ;call kernel mov eax, 1 ;system call number (sys_exit) int 0x80 section .data result db 6, 13, 10, 0 ;массив для вывода