Чем dw и dd отличаются от директив db для строк?

Допустим, я хочу определить инициализированную строку переменной перед запуском моей программы сборки (в section .data). Переменная, которую я выбрал для создания, называется Digits, и это строка, содержащая все шестнадцатеричные символы.

Digits: db "0123456789ABCDEF"

Я определил переменную с помощью db, что означает определение байта. Означает ли это, что переменная Digits имеет длину 8 бит? Для меня это не имеет смысла, потому что:

Каждый символ в строке является символом ASCII, поэтому мне понадобится 2 байта для каждого символа. Всего на всю строку мне понадобится 32 байта!

Итак, что это значит, когда я определяю переменную как byte? Word? Двойное слово? Я не вижу разницы. Из-за моего непонимания кажется излишним указывать тип данных, которые вам нужны для строки.

PD: Этот вопрос не помогло мне понять.


person Pichi Wuana    schedule 09.08.2016    source источник
comment
@ JoseManuelAbarcaRodríguez Я знаю, что я определяю байтовую переменную. Что если я определю словесную переменную? Будет ли это 16 слов, например 32 байта? Для меня это не имеет смысла ... Я что-то упускаю. Все построено из байтов, поэтому не должно ли все быть байтовой переменной?   -  person Pichi Wuana    schedule 09.08.2016
comment
Пример: my_array DW 1,2,3,4, эта переменная содержит 4 значения, каждое значение имеет длину 2 байта, поэтому переменная имеет размер 8 байтов.   -  person Jose Manuel Abarca Rodríguez    schedule 09.08.2016
comment
@ JoseManuelAbarcaRodríguez Но в случае со строками? Именно здесь я ошибаюсь, когда определяю строки.   -  person Pichi Wuana    schedule 09.08.2016
comment
С типами DB, DW или DD вы указываете, сколько памяти нужно зарезервировать, но память всегда представляет собой группу байтов.   -  person Jose Manuel Abarca Rodríguez    schedule 09.08.2016
comment
Пичи Вуана: какой компилятор вы используете? В моем компиляторе данные упорядочены в зависимости от типа: для типа DB байты сохраняют заданный порядок, для DW каждые два байта меняют свой порядок ('ab' хранится как 'ba'), а для DD каждые 4 байта меняют свой порядок (abcd сохраняется как dcba). Этот порядок меняется, потому что компилятор сохраняет первый байт в младших 8 битах, второй байт в следующих 8 битах и ​​так далее. Может, это то, что вас смущает.   -  person Jose Manuel Abarca Rodríguez    schedule 10.08.2016
comment
Не думайте об этом как об определяющих переменных; вы определяете метки для ячеек / выделений памяти.   -  person David Hoelzer    schedule 10.08.2016
comment
ASCII - это 8-битная кодировка (на самом деле классический ASCII - только 7-битный, коды выше 0x80 зависят от платформы, кодировка ISO-Latin1 часто используется в настоящее время). Итак, '0123456789ABCDEF` - это 16 байтов, а не 32. Digits: db как бы равнозначно do Digits: db '0', а затем на новой строке делает db '1', '2', '3', ...'F'. (значит, метка Digits имеет адрес байта, содержащего «0»). Синтаксис 'string' - это ярлык для определения значений нескольких байтов.   -  person Ped7g    schedule 10.08.2016


Ответы (3)


Ответ NASM: MASM совершенно другой

Один из ответов на связанный вопрос содержит цитату из примеров руководства NASM, которая действительно отвечает на ваш вопрос. По запросу я расширю его для всех трех случаев (и исправлю ошибку кодирования ASCII в нижнем и верхнем регистре!):

db   'ABCDE'     ; 0x41 0x42 0x43 0x44 0x45                (5 bytes)
dw   'ABCDE'     ; 0x41 0x42 0x43 0x44 0x45 0x00           (6 bytes, 3 words)
dd   'ABCDE'     ; 0x41 0x42 0x43 0x44 0x45 0x00 0x00 0x00 (8 bytes, 2 doublewords)
dq   'ABCDE'     ; 0x41 0x42 0x43 0x44 0x45 0x00 0x00 0x00 (8 bytes, 1 quadword)

Таким образом, разница в том, что он дополняется нулями до кратного размера элемента, когда вы используете dd или dw вместо db.

Согласно комментарий Хосе, некоторые ассемблеры могут использовать другой порядок байтов для строковых констант dd или dw. В синтаксисе NASM строка всегда сохраняется в памяти в том же порядке, в котором она отображается в указанной константе.

Вы можете собрать это с помощью NASM (например, в плоский двоичный вывод по умолчанию) и использовать hexdump -C или что-то еще, чтобы подтвердить порядок байтов и количество отступов.


Обратите внимание, что это дополнение к размеру элемента применяется к каждому элементу, разделенному запятыми. Итак, внешне невинный dd '%lf', 10, 0 на самом деле собирается так:

;dd   '%lf',    10,        0
db    '%lf',0,  10,0,0,0,  0,0,0,0        ;; equivalent with db

Обратите внимание на 0 перед новой строкой; если вы передадите указатель на это printf, строка C будет просто "%lf", оканчивающаяся первым 0 байтом.

(write системный вызов или fwrite функция с явной длиной будет печатать все это, включая 0 байтов, потому что эти функции работают с двоичными данными, а не с строками неявной длины C.)


Также обратите внимание, что в NASM вы можете делать такие вещи, как mov dword [rdi], "abc", для сохранения abc \ 0 в памяти. т.е. многосимвольные литералы работают как числовые литералы в любом контексте в NASM.


MASM очень отличается

См. При использовании мнемоники MOV для загрузки / копирования строки в регистр памяти в MASM символы сохраняются в обратном порядке? подробнее. Даже в dd "abcd" MASM разбивает ваши строки, меняя порядок байтов внутри фрагментов на обратный по сравнению с исходным порядком.

person Peter Cordes    schedule 09.08.2016
comment
Можете ли вы показать пример для каждого из двух других случаев, как вы показали в комментарии, как это происходит с dw? - person Pichi Wuana; 10.08.2016
comment
В заключение, мнемоника на самом деле ничего не меняет в переменной, только когда это таблицы? - person Pichi Wuana; 10.08.2016
comment
@PichiWuana: Я бы не так это описал. db с отдельной директивой ALIGN будет иметь больше смысла, если вы собираетесь обращаться к нему как к отдельным байтам. Кроме того, db просто собирает байты в выходной файл. Переменные - это концепция более высокого уровня, которой не нужно сопоставлять 1: 1 с директивами или метками. - person Peter Cordes; 10.08.2016
comment
Что касается ассемблеров, которые меняют байты в строке, сравните этот источник NASM с этим источником A86: Для A86 двухбайтовые строковые элементы dw инвертируются ассемблером, поэтому источник должен содержать обратные строки. - person ecm; 15.04.2021

Хочу кое-что уточнить:

example: db 'ABCDE';

Всего резервируется 5 байтов, каждый из которых содержит букву.

ex2: db 1 ;

резервирует байт, содержащий 1

ex3: db "cool;

резервирует 4 байта, и каждый байт содержит букву

ex4: db "cool", 1, 3;

резервирует 3 байта?

ответы: ex4 составляет 6 байтов

person opobtdfs    schedule 03.06.2020
comment
Поместите это в файл, соберите его и создайте шестнадцатеричный дамп, чтобы увидеть, что ваш ассемблер поместил туда. Ваш последний пример неверен, "cool", 1, 3 всего 6 байт. - person Peter Cordes; 04.06.2020
comment
Кроме того, это не совсем ответ. Это как бы вопрос, хотя первые 3 примера - правильные ответы. - person Peter Cordes; 04.06.2020
comment
@PeterCordes Да, я понял ответ. Спасибо - person opobtdfs; 04.06.2020
comment
Затем отредактируйте свой ответ, чтобы исправить информацию, которую вы оставляете для будущих читателей. Или удалите его, если на самом деле вы не хотите убирать вопросы и превращать их в правильный ответ. - person Peter Cordes; 04.06.2020

Для каждого символа в строке «0123456789ABCDEF» вам понадобится всего один байт. Итак, строка займет в памяти 16 байт.

В случае этого объявления:

vark db 1

вы можете сделать это:

mov [vark], 128

и не может:

mov [vark], 1024

но в этом случае:

vark dw 1

вы можете.

person skaa    schedule 09.08.2016
comment
OP не указывал MASM, где директивы после метки волшебным образом влияют на размер операнда инструкций, ссылающихся на нее. Кроме того, это вообще не отвечает на вопрос, поскольку этот вопрос касается конкретно строк, а не целочисленных констант, таких как Q, связанный с OP, и сказал, что не ответил на его вопрос. - person Peter Cordes; 10.08.2016