Да, вы должны объявить в «конструкторе», если хотите, чтобы список стал свойством объекта, а не свойством класса.
Первый из них equate
, аналогичный C:
#define len 2
тем, что он фактически не выделяет какое-либо пространство в конечном коде, он просто устанавливает символ len
равным 2. Затем, когда вы используете len
позже в своем исходном коде, это то же самое, что если вы используете константу 2
.
Вторая - define byte
, аналогичная C :
int len = 2;
Он действительно фактически выделяет пробел, один байт в памяти, сохраняет там 2
и устанавливает len
как адрес этого байта.
Вот какой-то код psuedo-ассемблера, который показывает различие:
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
.
Сводка
NASM 2.10.09 Выход ELF:
db
не имеет никаких магических эффектов: он просто выводит байты непосредственно в выходной файл объекта. Если эти байты находятся перед символом, символ будет указывать на это значение при запуске программы. Если вы находитесь в текстовом разделе, ваши байты будут выполнены. Погода, которую вы используете db
или dw
и т. Д., Которая не указывает размер символа: поле st_size
в записи таблицы символов не влияет. equ
делает символ в текущей строке есть волшебное значение st_shndx == SHN_ABS
в его записи в таблице символов. Вместо вывода байта в текущее местоположение объекта объекта он выводит его в поле st_value
записи в таблице символов. Все остальное следует из этого.
Чтобы понять, что это на самом деле означает, вы должны сначала понять основы стандарта ELF и relocation .
Теория SHN_ABS
SHN_ABS
сообщает компоновщику, что:
st_value
записи символа должно использоваться как значение непосредственно Контрастируйте это с «регулярными» символами, в которых значение символа является адресом памяти вместо этого, и поэтому необходимо переместить.
Поскольку это не указывает на память, символы SHN_ABS
могут быть эффективно удалены из исполняемого файла компоновщиком, вставляя их.
Но они все еще являются регулярными символами в объектных файлах, а делают там, где есть глобальная память.
Пример использования
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
is 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 состоит в том, чтобы определить данное имя метки для значения его (только) операнда. Это определение является абсолютным и не может измениться позже. Так, например,
blockquote>message db 'hello, world' msglen equ $-message
определяет msglen как константу 12. msglen не может затем переопределяться позже. Это также не определение препроцессора: значение msglen оценивается один раз, используя значение $ (см. Раздел 3.5 для объяснения $) в точке определения, вместо того, чтобы оцениваться везде, где оно ссылается, и используя значение $ в точке отсчета.
blockquote>См. также
Аналогичный вопрос для GAS: Разница между .equ и .word в ARM Assembly?
.equiv
, похоже, закрывает эквивалент GAS.
equ: время препроцессора. аналогично #define, но большинству ассемблеров не хватает #undef и не может иметь ничего, кроме атомной константы с фиксированным числом байтов с правой стороны, поэтому поплавки, удваивает, списки не поддерживаются большинством директив equals для ассемблеров.
db: время компиляции. значение, хранящееся в db, сохраняется на двоичном выходе ассемблером при определенном смещении. equ позволяет вам определять константы, которые обычно должны быть либо жестко запрограммированы, либо потребовать операцию mov для получения. db позволяет вам иметь данные в памяти до того, как программа даже начнется.
Вот демон nasm, демонстрирующий db:
; 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
. Equ может определять только константу вплоть до наибольшего, что поддерживает ассемблер
пример 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 get заменяются правой частью этого equ.