Инструкция по сборке для записи строки ASCII - PullRequest
0 голосов
/ 31 августа 2018

Я сейчас пишу процедуру сборки, и я что-то не понимаю.

Я должен написать, например, строку «000-00» в файле .txt, процедура здесь (процедура читает в стеке указатель выходного файла и записывает строку на нем) (процедура вызывается из программы переменного тока):

.data
.section .text
.global func

func:
      pushl %ebp
      movl %esp, %ebp

      pushl %edi
      pushl %esi

      movl 12(%ebp), %edi
      movl $VAL, (%edi)
      movl $VAL2, 4(%edi)

      popl %esi
      popl %edi
      popl %ebp
      ret

в строке:

movl $VAL, (%edi) 

VAL должно быть значением, которое позволяет мне записать (% edi) строку 000-00. Что мне нужно сделать? Преобразовать строку в ASCII? Я знаю, что в ASCII '0' равно 48, я подумал, что должен был написать $ 48484845 для (48 -> '0' и 45 -> '-')

поэтому я подумал, что строка 000- была равна 48484845 в ASCII. Что я делаю неправильно? ПОЧЕМУ, если я напишу:

movl $48, (%edi) 

вывод правильный, и в файле .txt я прочитал символ 0, я просто не понимаю, как написать несколько символов ascii в одной инструкции.

Спасибо за ответы и прошу прощения за мой плохой английский.

РЕДАКТИРОВАТЬ: Я нашел это значение:

movl $757935149, (%edi)

и эта инструкция напишет строку "-, -" я не постоянный, ASCII для "-" - 45, а "," - 44 ...

1 Ответ

0 голосов
/ 31 августа 2018

VAL должно быть значением, которое позволяет мне записать (% edi) строку 000-00. Что мне нужно сделать? Преобразовать строку в ASCII? я знаю это «0» в ASCII - 48, я подумал, что должен был написать $ 48484845 для (48 -> «0» и 45 -> '-')

так что я думал, что строка 000- была равна 48484845 в ASCII. Какие я делаю не так?

Вы очень близки, но вы полностью пропускаете часть, как значения кодируются в компьютере. movl сохраняет 32 бита в памяти, и память адресуется байтами (8 бит), а символы, закодированные в ASCII, обычно хранятся как один байт = один символ ASCII (даже если для чистого ASCII требуется только 7 бит, поэтому 8-й бит всегда равен нулю).

Итак, вам нужно значение VAL, которое сохранит в памяти четыре байта: 48, 48, 48, 45.

Но у вашего десятичного значения 48484845 есть две проблемы: во-первых, когда вы проверите, как это значение выглядит в двоичном формате, это 0000_0010_1110_0011_1101_0001_1110_1101 (или в шестнадцатеричном 0x2E3D1ED), а x86 - система с прямым порядком байтов, так что эти 32 биты будут разделены и записаны в память в виде байтов 1110_1101 (237 или 0xED), 1101_0001 (209 или 0xD1), 1110_0011 (227 или 0xE3) и 0000_0010 (2 или 0x02). Младший порядок означает, что младшие 8 бит идут в память первыми (по адресу edi+0), а старшие 8 бит идут в память последними (по адресу edi+3).

Таким образом, вам нужно поместить три значения «48» в младшие 24 бита, а значение «45» - в старшие 8 бит, т. Е. Вам нужно значение 48 + 48*256 + 48*256*256 + 45*256*256*256 = 758132784, которое при преобразовании в шестнадцатеричное значение будет 0x2D303030. *256 будет «сдвигать» значение на 8 бит вверх, потому что 2 8 = 256.

Теперь, если вы обратите внимание на эти шестнадцатеричные значения, вы можете заметить, что каждая шестнадцатеричная цифра построена ровно из 4 бит (в то время как десятичные цифры 0,9) распределены по 4 битам, частично разделенным с предыдущей / следующей цифрой, поэтому они не так просто составить / извлечь из двоичного файла), и при значении 0x2D303030 его действительно можно прочитать в голове и увидеть отдельные байты как 2D_30_30_30, и поскольку они будут храниться в памяти в порядке младшего байта, память будет установлен в четыре байта (в шестнадцатеричном формате): 30 30 30 2D, который при прочтении в виде строки ASCII будет образовывать "000-" Поэтому, если вам нужно определить некоторую константу, в которой вы хотите установить конкретные биты, и вы не хотите использовать калькулятор или записывать в исходном коде (48 + 48 * 256), вы часто можете уйти, определив его в шестнадцатеричном формате, например например, 0x8001 для установки верхнего и нижнего бита 16-битного значения, а также каждые две шестнадцатеричные цифры образуют ровно один байт (8 бит), поэтому вы можете видеть в форматировании гекса отдельные значения байтов больших типов (например, word / dword / qword) (Кстати, 0x8001 - это 32769 в десятичном виде, это то, что я могу вычислить в голове, потому что у меня первые 16 степеней двух запечатлены в памяти после программирования 8-битных компьютеров, поэтому старший бит равен 2 15 = 32768, а нижний бит равен 2 0 = 1 ... но шестнадцатеричное форматирование намного проще и удобнее для задач такого рода).

BTW movl $48,(%edi) записывает 4 байта (суффикс "l" в mov означает "long" = 32-битное значение), поэтому вы пишете четыре символа: 48, 0, 0, 0. Также ваша исходная задача: если вы должны вывести действительно только «000-00» и ничего больше, то вторая mov с VAL2 должна быть movw $0x3030, 4(%edi) для записи только двух байтов в память, с movl вы будете хранить значение 0x3030 как четыре байта 48, 48, 0, 0, то есть добавление двух обнуленных байтов после строки.

Опять же, если подпрограмма вызывающая сторона зарезервировала достаточно места для строкового буфера (не менее 8 байт) и записывает только 6 байт в файл на диске, вторая movl безвредна. Если вызывающая сторона будет иметь только 6-байтовый буфер, то вторая movl будет ошибкой переполнения буфера.

...