В чем разница между equ и db в NASM? - PullRequest
19 голосов
/ 04 ноября 2011
len:  equ  2
len:  db   2

Являются ли они одинаковыми, производя ярлык, который можно использовать вместо 2? Если нет, то в чем преимущество или недостаток каждой формы декларации? Могут ли они быть взаимозаменяемыми?

Ответы [ 3 ]

32 голосов
/ 04 ноября 2011

Первый - equate, аналогично C:

#define len 2

в том смысле, что он фактически не выделяет пробела в конечном коде, он просто устанавливает символ len равным 2. Затем, когда вы позже используете len в своем исходном коде, это то же самое как будто вы используете константу 2.

Второй - define byte, аналогично C:

int len = 2;

Он действительно фактически выделяет пространство, один байт в памяти, сохраняет там 2 и устанавливает len в качестве адреса этого байта.

Вот некоторый код псевдо-ассемблера, который показывает различие:

line   addr   code       label   instruction
----   ----   --------   -----   -----------
   1   0000                      org    1234
   2   1234              elen    equ    2
   3   1234   02         dlen    db     2
   4   1235   44 02 00           mov    ax     elen
   5   1238   44 34 12           mov    ax     dlen

В строке 1 просто задается адрес сборки, равный 1234, чтобы упростить объяснение происходящего.

В строке 2 код не генерируется, ассемблер просто загружает elen в таблицу символов со значением 2. Поскольку код не был сгенерирован, адрес не меняется.

Затем, когда вы используете его в строке 4, оно загружает это значение в регистр.

Строка 3 показывает, что db отличается, она фактически выделяет некоторое пространство (один байт) и сохраняет значение в этом пространстве. Затем он загружает dlen в таблицу символов, но дает ему значение этого адреса 1234, а не постоянное значение 2.

Когда вы позже используете dlen в строке 5, вы получите адрес, по которому вам нужно будет разыскивать фактическое значение 2.

2 голосов
/ 27 января 2018

equ : время препроцессора. аналогично #define, но большинству ассемблеров не хватает #undef, и он не может иметь ничего, кроме атомарной константы с фиксированным числом байтов в правой части, поэтому плавающие, двойные, списки не поддерживаются директивой equ большинства ассемблеров.

дБ : время компиляции. значение, хранящееся в дБ, сохраняется в двоичном выводе ассемблером с определенным смещением. equ позволяет вам определять константы, которые обычно должны быть либо жестко закодированы, либо требовать операции mov для получения. БД позволяет вам иметь данные в памяти еще до запуска программы.

Вот нос, демонстрирующий ДБ:

; I am a 16 byte object at offset 0.
    db '----------------'

; I am a 14 byte object at offset 16
; the label foo makes the assembler remember the current 'tell' of the 
; binary being written.
foo:
    db 'Hello, World!', 0

; I am a 2 byte filler at offset 30 to help readability in hex editor.
    db ' .'

; I am a 4 byte object at offset 16 that the offset of foo, which is 16(0x10).
    dd foo

enter image description here

Эквивалент может определять только константу с точностью до наибольшей, поддерживаемой ассемблером

пример equ, вместе с несколькими общими ограничениями.

; OK
ZERO equ 0

; OK(some assemblers won't recognize \r and will need to look up the ascii table to get the value of it).
CR equ 0xD
; OK(some assemblers won't recognize \n and will need to look up the ascii table to get the value of it).
LF equ 0xA

; error: bar.asm:2: warning: numeric constant 102919291299129192919293122 -
; does not fit in 64 bits
; LARGE_INTEGER equ 102919291299129192919293122

; bar.asm:5: error: expression syntax error
; assemblers often don't support float constants, despite fitting in
; reasonable number of bytes. This is one of the many things
; we take for granted in C, ability to precompile floats at compile time
; without the need to create your own assembly preprocessor/assembler.
; PI equ 3.1415926 

; bar.asm:14: error: bad syntax for EQU
; assemblers often don't support list constants, this is something C
; does support using define, allowing you to define a macro that
; can be passed as a single argument to a function that takes multiple.
; eg
; #define RED 0xff, 0x00, 0x00, 0x00
; glVertex4f(RED);
; #undef RED
;RED equ 0xff, 0x00, 0x00, 0x00

полученный бинарный файл вообще не имеет байтов, потому что equ не загрязняет изображение; все ссылки на equ заменяются правой частью этого equ.

2 голосов

Сводка

NASM 2.10.09 Выход ELF:

  • db не имеет магических эффектов: он просто выводит байты напрямуюв выходной объектный файл.

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

    Если вы находитесь в текстовом разделе,Ваши байты будут выполнены.

    Погода, которую вы используете db или dw и т. д., которая не определяет размер символа: поле st_size записи таблицы символов не затрагивается.

  • equ заставляет символ в текущей строке иметь st_shndx == SHN_ABS магическое значение в своей записи таблицы символов.

    Вместо вывода байта в текущее местоположение объектного файлаон выводит его в поле st_value записи таблицы символов.

Все остальное следует из этого.

Чтобы понять, что это на самом деле означает, вам следует сначалапонять основы стандарта ELF и перемещение .

Теория SHN_ABS

SHN_ABS сообщает компоновщику, что:

  • перемещение не должно выполняться для этого символа
  • поле st_value для ввода символа должно использоваться как значение непосредственно

Сравните это с "обычными" символами, в которых значение символа вместо адреса памяти,и поэтому должен пройти через перемещение.

Так как он не указывает на память, символы SHN_ABS могут быть эффективно удалены из исполняемого файла компоновщиком, вставив их.

Но они все еще обычныесимволы в объектных файлах и do занимают там память и могут быть распределены между несколькими файлами, если они глобальные.

Пример использования

section .data
    x: equ 1
    y: db 2
section .text
global _start
_start:
    mov al, x
    ; al == 1
    mov al, [y]
    ; al == 2

Обратите внимание, что, поскольку символ x содержит буквальное значение, разыменование [] не должно выполняться с ним, как для y.

Если мы хотим использовать x из программы на C, мы 'мне нужно что-то вроде:

extern char x;
printf("%d", &x);

и установить на asm:

global x

Эмпирическое наблюдение за сгенерированным выходом

Мы можем наблюдать то, что мы говорили ранее:

nasm -felf32 -o equ.o equ.asm
ld -melf_i386 -o equ equ.o

Сейчас:

readelf -s equ.o

содержит:

Num:    Value  Size Type    Bind   Vis      Ndx Name
  4: 00000001     0 NOTYPE  LOCAL  DEFAULT  ABS x
  5: 00000000     0 NOTYPE  LOCAL  DEFAULT    1 y

Ndx равно st_shndx, поэтому мы видим, что x равно SHN_ABS, а y нет.

Также видно, что Size равно0 для y: db никоим образом не сказал y, что это был один байт в ширину.Мы могли бы просто добавить две директивы db, чтобы выделить там 2 байта.

И затем:

objdump -dr equ

дает:

08048080 <_start>:
 8048080:       b0 01                   mov    $0x1,%al
 8048082:       a0 88 90 04 08          mov    0x8049088,%al

Итак, мы видим, что 0x1 был встроен в инструкцию, а y получил значение адреса перемещения 0x8049088.

Протестировано в Ubuntu 14.04 AMD64.

Документы

http://www.nasm.us/doc/nasmdoc3.html#section-3.2.4:

EQU определяет символ для данного постоянного значения: когда используется EQU, строка источника должна содержать метку.Действие EQU состоит в том, чтобы определить данное имя метки для значения его (единственного) операнда.Это определение является абсолютным и не может измениться позже.Так, например,

message         db      'hello, world' 
msglen          equ     $-message

определяет msglen как постоянную 12. msglen не может быть затем переопределен позже.Это также не определение препроцессора: значение msglen оценивается один раз, используя значение $ (объяснение $ см. В разделе 3.5) в точке определения, а не вычисляется там, где на него ссылаются, и используя значение$ в точке отсчета.

См. также

Аналогичный вопрос для GAS: Разница между .equ и .word в ARM Assembly? .equiv похоже на закрытый эквивалент ГАЗА.

...