На принципиальном уровне вы используете .lcomm d2, 255
для выделения 255 байтов для строковых данных. Один байт - 8 бит, 1 бит - 0 или 1. Таким образом, максимальное значение одного байта равно 2 -1 при обработке двоичного значения без знака. Что для меня наиболее распространенным способом, как я думаю о байтах (как число 0..255
), но эти 8 бит могут представлять и другие значения, например, используется иногда подписанный 8-бит (-128..+127
) или конкретные биты, функциональность для доступа к конкретному коду. (Эта часть хорошо)
Затем вы используете scanf
с "%s\0\n"
определения (он будет компилировать как байты '%', 's', 0, 10
... не уверен, что 10 хорошо для там после нулевого терминатора). Вместо этого я использовал бы .asciiz "%254s"
, чтобы злоумышленник не ввел более 255 байтов ввода в это зарезервированное пространство d2
. (обратите внимание, что это .asciiz
с z
в конце, поэтому он добавит нулевой байт по своему усмотрению)
Затем вы используете printf
. Скорее предоставим другую строку форматирования отдельно для вывода, на этот раз, как formatOut: .asciiz "%s\n"
.
Наконец-то вы хотите strlen
.
Это значит, что я вернусь обратно на вход. Если вы работаете в обычной 64-битной ОС (linux), ваша строка ввода очень вероятна в кодировке UTF-8 (если ваша ОС не установлена в другом конкретном локали, то я не уверен, какой Locale будет принимать scanf
).
Кодирование UTF-8 кодируется по переменной длине, поэтому вы должны решить, будет ли ваш strlen
возвращать количество символов или количество занятых байтов.
Для простоты я предполагаю, что для вас достаточно количества байтов (не символов), и если ваши входные строки будут состоять только из основных символов ASCII 7b ([0-9A-Za-z [email protected]#$%^&*,.;'\<>?:"|{}]
и т. Д. ... проверьте любую таблицу ASCII ... нет акцента разрешенные символы (например, á
), что приведет к созданию многобайтового кода UTF8), тогда количество байтов будет равно числу символов (кодировка UTF-8 является совместимой с 7b ASCII).
Это означает, например, для ввода "Hell 1234"
память по адресу d2
будет содержать эти значения (шестнадцатеричные) 48 65 6C 6C 20 31 32 33 34 00
. Еще раз, если вы проверите таблицу ASCII, вы поймете, что, например, байтом 0x20
является символ пробега и т. Д. И строка «nul terminated», последнее значение ноль является частью строки, но это не отображается, вместо этого он используется различными функциями C как «конец маркера строки».
Итак, что вы хотите сделать в strlen
, - это загрузить некоторые регистры с адресом d2
, скажем rdi
. И затем сканирование байта байтом (байт, поскольку кодировка ASCII работает в режиме «1 char = 1 байт», и мы будем игнорировать коды переменной длины UTF-8), пока вы не достигнете нулевого значения в памяти, а между тем подсчитайте, сколько байтов для этого потребовалось.Если вы подумаете над этой идеей немного, чтобы сделать ее «коротким» для процессора, и вы будете использовать SCASB
для сканирования (вы также можете записать ее «вручную» с обычным mov/cmp/inc/jne/jnz
, если хотите), вы можете завершить это:
rdi = d2 address
rdx = rdi ; (copy of d2 address)
ecx = 255 ; maximum length of string
al = 0 ; value to test against
repne scasb ; repeat SCASB instruction until zero is found
; here rdi points at the zero byte
; (or it's d2+255 if the zero terminator is missing)
rdi -= rdx ; rdi = length of string
; return result as you wish
Итак, вам нужно сначала правильно понять, с какими значениями вы управляете, где они находятся, каков их размер бит/байт и какая у него структура.
Затем вы можете написать инструкции, которые дают разумные расчеты на основе этих данных.
В вашем случае вычисление «length_of_string = количество ненулевых байтов в 7b закодированной в ASCII строке, хранящейся в памяти по адресу d2
» (я имею в виду после успешной части кода scanf
).
Учитывая, как выглядит ваш источник, мне кажется, что вы не понимаете, что такое инструкция по процессору x86, и вы просто скопируете их из некоторых примеров. Это скоро вызовет у вас неприятности.
Например, cmp 0, %rcx
проверяет, является ли rcx
(8 байтов «широким» значением) равна нулю. И вы загрузили rcx
со значением от rdx
, что было чем-то из стека (возможно, d2
адрес), поэтому rcx
никогда не будет равен нулю.
И даже если вы на самом деле загружает символьные значения из памяти в rcx
, вы нагрузили бы 8 из них в то же время, так что вы пропустили бы значение 0
, как это будет только один байт внутри некоторого мусора, как 0xCCCCCCCC00343332
(Я использую 0xCC
для неопределенной памяти после d2
буфера, например, может быть любое значение).
Так что код не имеет никакого смысла. Если вы хотя бы частично понимаете, что такое регистры процессора и какие инструкции, например, mov/inc/cmp/...
, то у вас есть шанс создать рабочий код, просто используя отладчик, чтобы проверить почти каждые 1-2 новых инструкций, добавленных в исходный код, если он манипулирует правильные значения и исправить их, пока не получите правильное значение.
Для этого необходимо, чтобы у вас было четкое представление о том, что такое «правильное поведение»! (как в этом случае "выборка байтов по байтам от d2
адрес, один за другим, увеличение счетчика длины и поиск нулевого байта). Таким образом, вы можете узнать, когда код делает то, что вам нужно, или нет.
Я хотел бы указать на этот ответ: сами инструкции, хотя и важны, менее важны, чем ваше видение используемых данных/структур/алгоритмов. Ваш вопрос звучит так, будто вы понятия не имеете, что такое «C string "в сборке x86 или какой алгоритм использовать. Это делает невозможным просто« угадать »некоторые инструкции в исходном коде, а затем проверить, правильно ли вы догадались. Потому что вы не можете сказать, что вы хотите. Вот почему я сказал, что вы должны проверить также не связанные с газом ресурсы сборки x86 для самых основ, что такое бит/байт/compu ter memory/etc ... вверх до тех пор, пока вы не поймете, какие числовые значения обрабатываются, например, для создания «строк».
После того, как вы будете иметь хорошее представление о том, что он должен сделать, это будет легко для вас, чтобы поймать в отладочных вещи, как поменялись местами аргументы (например: movq %rcx, d2
- почему вы положили 8 байт из rcx
в память по адресу d2
Что? перезаписывает входную строку) и тому подобное, поэтому вам не нужно понимать инструкции и синтаксис газа на 100% хорошо, достаточно, чтобы что-то создать, а затем несколько итераций, чтобы «исправить» его.Как проверить представление регистра + памяти, реализуя rcx
не изменилась, но вместо того, чтобы строковые данные были повреждены => попробовать это другой способ ...
О, и я совсем забыл ... Вам нужно найти документацию для вашей 64-битной платформы ABI, чтобы вы знали, что это правильный способ передать аргументы в функции C.
Например, в Linux эти уроки могут помочь: http://cs.lmu.edu/~ray/notes/gasexamples/
И поиск здесь слово «ABI» для дополнительных ресурсов: https://stackoverflow.com/tags/x86/info
Как любезно, пожалуйста, исправить форматирование, если вы видите, что выходит перепутались. Нажмите ссылку [edit] (http://stackoverflow.com/posts/41452817/edit) под сообщением и используйте кнопку «образец кода» на панели инструментов. Что касается вашей проблемы, лучше прокомментируйте свой код, опишите действительное и ожидаемое поведение и научитесь использовать отладчик. – Jester
Я не проверял себя, насколько это хорошо, но просто чтобы сделать ваше заявление * «ничего подходящего онлайн» * смешно, например: https://www.youtube.com/playlist?list=PLKK11Ligqiti8g3gWRtMjMgf1KoKDOvME (одна целая часть посвященный газу, и вы должны стараться смотреть на других, вероятно, тоже, из названий он выглядит как хорошие основы, вступительные в то, что вы должны понимать, прежде чем пытаться изучить синтаксис газа x86-64). – Ped7g
извините! Я попытался добавить commetd, но они просто ушли, и как-то я не могу больше редактировать, некоторые ошибки. –