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
будет ошибкой переполнения буфера.