Перенос значения меньшего размера в регистр
Я сохранил однобайтовое значение 8
и я бы хотел переместить это в rax
регистр. Я сейчас делаю это сmovzx
чтобы обнулить байт:
.globl main
main:
push %rbp
mov %rsp, %rbp
movb $8, -1(%rbp)
movzx -1(%rbp), %rax <-- here
...
Каким образом movzx
инструкция "знать", что значение в -1(%rbp)
всего один байт? Отсюда говорится, если я правильно его читаю, что он может работать как наbyte
и word
, но откуда ему знать? Например, если я добавил двухбайтовое значение в-2(%rbp)
как он узнает, что нужно получить двухбайтовое значение? Есть еще инструкция, где я могу просто взятьone
или two
или four
байтовое значение по адресу и вставить его в 64-битный регистр?
Я полагаю, что другой способ сделать это - сначала обнулить регистр, а затем добавить его к 8-битному (или сколько угодно битному) компоненту, например:
mov $0, %rax
mov -1(%rbp), %al
Есть ли один способ предпочтительнее другого?
2 ответа
Каким образом
movzx
инструкция "знать", что значение в-1(%rbp)
всего один байт?
Есть две (а то и три) инструкции:
movzxb
(-1(%rbp)
длиной в один байт) и movzxw
(-1(%rbp)
состоит из одного 16-битного слова).
Мой ассемблер интерпретирует movzx
как movzxb
; однако полагаться на это не стоит!
Лучше используйте имя инструкции, включая размер источника (movzxb
или movzxw
), чтобы ассемблер использовал правильную инструкцию.
Это неоднозначно и зависит от некоторого значения по умолчанию, вы не должны писать такой код.
Вот почему синтаксис AT&T movzb
а также movzw
инструкции (обычно используются как movzbl -1(%rbp), %eax
) для двух разных размеров исходного кода Intel-синтаксиса movzx
мнемоника. См. Стандартизирована ли мнемоника сборки x86?(нет, AT&T придумывает новые имена.)
И да, ты мог xor %eax,%eax
/ mov -1(%rbp), %al
для слияния с младшим байтом, но это бессмысленно неэффективно. x86-64 гарантирует доступность 386 инструкций, таких как movzx.
Удивительно, movzx -1(%rbp), %rax
собирается. Если вы соберете его, затем разоберите обратно в синтаксис AT&T с помощьюobjdump -d foo.o
, Вы получаете movzbq
(от байта до четырех), включая бесполезный префикс REX вместо того, чтобы позволить неявному нулевому расширению выполнить работу после записи EAX.
48 0f b6 45 ff movzbq -0x1(%rbp),%rax
Или выполните дизассемблирование в синтаксис Intel с помощью objdump -drwC -Mintel
:
48 0f b6 45 ff movzx rax,BYTE PTR [rbp-0x1]
Интересный факт: ГАЗ не может делать выводов movzb
vs. movzw
если вы напишете просто movz
, потому как movz
не является мнемонической инструкцией. В отличие от суффиксов размера операнда, которые могут быть выведены из операндов,b
а также w
рассматриваются как часть мнемоники. Но ты можешь написатьmovzx
а затем он будет определять оба размера из операндов регистров, как в режиме синтаксиса Intel.
5: 0f b6 c0 movzbl %al,%eax # source: movzx %al, %eax
8: 0f b7 c0 movzwl %ax,%eax # source: movzx %ax, %eax
movzw
а также movzb
действуют как мнемоники инструкций сами по себе (которые могут выводить суффикс размера из регистра назначения). Наполовину связанный: что делает инструкция MOVZBL в синтаксисе IA-32 AT&T?
Также по теме: таблица cdq и т. Д. Эквиваленты с точки зрения movsx
и эквиваленты AT&T: что делает cltq в сборке?
Также связано: MOVZX отсутствует 32-битный регистр в 64-битном регистре - потому что это неявно при записи 32-битного регистра.