Перенос значения меньшего размера в регистр

Я сохранил однобайтовое значение 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-битного регистра.

Другие вопросы по тегам