Это третья часть серии

Теперь, когда мы создали эффективную среду разработки, пришло время написать реальный код на языке ассемблера. В этом руководстве я расскажу о ресурсах и процессах, которым я следовал при создании простой программы на языке ассемблера.

Печать аргументов командной строки

Чтобы продемонстрировать концепции, давайте напишем ассемблерную программу, которая подсчитывает количество уникальных слов в текстовом файле, имя которого предоставляется в качестве аргумента.

В качестве первого шага к этой цели программе потребуется доступ к аргументам командной строки. Эта первая программа посвящена пониманию того, как получить доступ к аргументам командной строки с помощью сборки Linux x86_64.

Если вы новичок в программировании на ассемблере, я предлагаю это руководство в качестве отправной точки для изучения некоторых основ. Я ссылаюсь на некоторые концепции здесь без дополнительных пояснений.

Что такое аргумент командной строки

Аргументы командной строки - это текстовые входные данные, которые пользователи программы включают в командную строку при выполнении программы. Например, если есть исполняемая программа с именем a.out, ее можно запустить в системе Linux из командной строки с помощью команды

$ ./a.out

Кроме того, после имени исполняемого файла можно указать «аргументы командной строки». Например,

$ ./a.out 1 2 3

В этом случае есть три аргумента: 1, 2 и 3.

Стек вызовов

Это поможет понять стек вызовов, поскольку именно здесь хранятся аргументы командной строки, когда программа начинает выполняться.

Если вы не знакомы, стек - это структура данных Last In First Out (LIFO), которая находится в оперативной памяти компьютера. Указатель стека отслеживает верх стека. В x86_64 указателем стека является регистр $rpi. $rpi - это указатель на последний адрес памяти стека. Указатель стека может использоваться для доступа к стеку или могут использоваться две команды языка ассемблера: push и pop. push можно использовать для добавления значения в стек и обновления $rpi, чтобы указать на это новое добавленное значение. pop можно использовать для получения значения Последний вход из стека и обновления $rpi, чтобы он указывал на следующее значение в стеке. Формат этих команд (обратите внимание, что точка с запятой используется для обозначения комментариев на языке ассемблера, поэтому все, что находится после ;, игнорируется компилятором):

; add the value of $rcx to the stack
push rcx
; pop the "Last In" stack value into $rbx. 
; In this case, the value of $rcx
pop rbx

Доступ к аргументам командной строки на языке ассемблера X86–64

Когда программа начинает выполнение, все аргументы командной строки сохраняются в стеке. Верх стека будет содержать количество аргументов. Если вы программировали в c или c++, это обозначается как argc в main(), что означает количество аргументов.

Второе значение в стеке - это имя функции. Это считается первым аргументом и включается в общее количество аргументов. Следовательно, если вы не укажете аргументов при выполнении программы, argc будет равно единице.

Любые предоставленные аргументы будут следующими значениями в стеке. Например, если вы выполнили программу с командой

./a.out arg1 arg2 arg3

стек будет выглядеть следующим образом

Стек

Указатель стека ($ rpi) будет указывать на вершину стека, то есть на адрес памяти значения argc, 4. Конечно, все эти значения будут закодированы в двоичном формате.

Эта программа выводит argc и имя программы с новой строкой между ними:

Обратите внимание на использование push и pop для извлечения argc и имени программы из стека.

Также важно использование команды call. Вот как можно вызвать функцию в сборке, сохранив адрес строки, следующей за строкой, которая вызвала функцию. Затем можно использовать команду ret для возврата к этой строке. Указатель на ячейку памяти места возврата сохраняется в стеке. Обратите внимание, что это значение удаляется из стека, чтобы разрешить доступ к «скрытым» значениям, затем оно помещается обратно в стек, потому что это то место, где команда ret ожидает адрес памяти.

Спасибо за прочтение! В следующей части этой серии вы найдете несколько советов по написанию вашей первой программы на ассемблере (скоро)!