Сборка - инструкция Mov и размер операндов

Когда мы используем команду mov в сборке, исходный и целевой операнды должны быть одного размера. Если я напишу:

mov rax, 1

Преобразован ли операнд 1 в соответствии с размером регистра rax?

Например, если rax 16 бит, мы получим:

0000000000000001

?

RAX 64-битный. В 64-битном режиме, как правило, непосредственные значения имеют либо 32 бита (расширенный знак, либо ноль), либо 64 бита.

Margaret Bloom 31.10.2018 11:30

@MargaretBloom: немедленные значения всегда расширяются знаком до размера операнда для кодов операций, которые используют узкие непосредственные. По крайней мере, я не могу придумать ни одного места, где они были бы нулевыми. Если вы хотите нулевое расширение, вы должны использовать mov eax, imm32, который имеет 32-битный размер операнда и следует обычному правилу записи 32-битного регистра с расширением нуля для заполнения 64-битного регистра. Почему инструкции x86-64 для 32-битных регистров обнуляют верхнюю часть полного 64-битного регистра?. (Я предполагаю, что это то, что вы имели в виду, но если мы рассмотрим более узкий размер операнда, то 16 и 8 бит будут

Peter Cordes 31.10.2018 11:41

Существует специальная инструкция movabs rax,<64b immediate>, которая будет содержать закодированное значение «1» как целое число 64b, но обычный современный ассемблер NASM, например, будет собирать mov rax,1 в инструкцию mov eax,1 с немедленным 32b (машинный код b8 01 00 00 00), которая установит окончательный контент rax в точном так же, но кодировка намного короче. .. В любом случае, если в инструкции есть rax в качестве целевого регистра, то вы можете сделать ставку, что любая выполняемая операция будет нацелена на все 64 бита целевого регистра. Как / если операнд расширен, зависит от конкретной инструкции и операнда.

Ped7g 31.10.2018 11:43

В любом случае, @koinos: см. Также Разница между movq и movabsq в x86-64 и В чем разница между инструкциями movq и movabsq x86-64 AT&T?, чтобы узнать больше о MOV, потому что MOV особенный; это единственная инструкция, которая может использовать 64-битную версию немедленно, поэтому существует несколько способов, которыми ассемблер может выбрать кодирование этого исходного кода asm в машинный код.

Peter Cordes 31.10.2018 11:43

@PeterCordes Да, но большинство ассемблеров будут кодировать mov rax, X как mov eax, X, если это возможно, поэтому полезно думать, что они расширены нулем (например, mov rax, 0xf0000000 составляет всего 5 байтов), хотя это технически не на 100% правильно.

Margaret Bloom 31.10.2018 12:08

@MargaretBloom: в целом да. Я понимаю, что я просто педантичен, но, похоже, вопрос, возможно, касался технических особенностей размера операнда. Неясно, о чем он на самом деле пытается спросить. Но я бы не сказал «большинство». NASM будет, но YASM - нет, и GAS .intel_syntax тоже. Я не знаю о FASM или MASM, и я не проверял clang / LLVM .intel_syntax, чтобы узнать, выполняет ли он оптимизацию во время сборки для другого размера операнда, поэтому полученный asm больше не ссылается явно на RAX.

Peter Cordes 31.10.2018 12:19

@PeterCordes О, я не знал, что это в основном функция NASM.

Margaret Bloom 31.10.2018 12:25

@MargaretBloom: Я думаю, что YASM считает это пропущенной оптимизацией, но я не уверен, что разработчики GAS примут патч, если кто-нибудь его отправит. Я не смотрел, хотят они этого или нет. Я предполагаю, что, возможно, нет, потому что возможность получить больше разных кодировок (для целей выравнивания кода) - это функция, и если они не добавят способ переопределить ее обратно в 7-байтовую кодировку, вы потеряете это. Теперь мне интересно узнать о MASM и FASM, потому что, если они это сделают, было бы несправедливо сказать, что это в основном функция NASM.

Peter Cordes 31.10.2018 12:48

@PeterCordes FASM, кажется, делает это, позвольте мне посмотреть, смогу ли я достать копию MASM.

Margaret Bloom 31.10.2018 12:59

Нет, извините @Peter, FASM этого не делает, а MASM делает.

Margaret Bloom 31.10.2018 13:12
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
10
2 623
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Есть 2 языка. Первый - это язык ассемблера, где у вас может быть строка символов вроде "mov rax, 1". Второй - машинный язык, где у вас будет набор байтов.

Эти языки родственные, но разные. Например, инструкция mov на языке ассемблера на самом деле представляет собой несколько различных кодов операций на машинном языке (один для перемещения байтов в / из регистров общего назначения, один для перемещения слов / двойных слов / слов в регистры общего назначения, один для перемещения двойных слов / слов для управления регистры, один для перемещения двойных слов / слов в регистры отладки и т. д.). Ассемблер использует инструкцию и ее операнды для выбора соответствующего кода операции (например, если вы выполняете mov dr6,eax, то ассемблер выберет код операции для перемещения dwords / qwords в регистры отладки, потому что ни один из других кодов операции не подходит).

Таким же образом могут быть разные операнды. Например, для языка ассемблера константа 1 имеет тип «целое число» и не имеет никакого размера (ее размер подразумевается из того, как / где она использовалась); но в машинном коде непосредственный операнд должен быть каким-то образом закодирован, и размер кодировки будет зависеть от того, какой код операции (и какие префиксы) используется для mov.

Например, если mov rax,1 преобразован в байты 0x48, 0xC7, 0xC0, 0x01, 0x00, 0x00, 0x00; тогда вы могли бы сказать, что операнд - это «64 бита, закодированные в 4 байта (с использованием расширения знака)»; или вы могли бы сказать, что операнд 32 бита, закодированный в 4 байта (и что инструкция перемещает только 32 бита в RAX, а затем знак распространяется на верхние 32 бита RAX вместо того, чтобы перемещать что-либо в них). Несмотря на то, что эти вещи звучат по-разному (и хотя большинство людей сказали бы, что последнее «более правильное»), поведение точно такое же, и единственные различия - это поверхностные различия в том, как машинный код (другой язык, не являющийся языком ассемблера) описан. На ассемблере 1 по-прежнему является («подразумеваемым из контекста») 64-битным операндом, независимо от того, что происходит на машинном языке.

Есть два кода операции для перемещения байтов в / из регистров GP (по одному для каждого направления). Или третий, если вы включаете mov reg, imm: немедленное перемещение байтов. И на самом деле вдвое больше, потому что есть другой код операции для 8-битного размера операнда по сравнению с 16/32/64 (тот же код операции с разными префиксами). Но в любом случае «один код операции для перемещения в / из регистров GP» определенно не совсем правильный. Ссылка на felixcloutier.com/x86/MOV.html здесь - хорошая идея.

Peter Cordes 31.10.2018 12:57

Ваш последний абзац читается так, как будто он описывает кодировку b8 01 00 00 00 (mov eax,imm32). В 7-байтовой кодировке, которую вы показываете, используется немедленное 32-битное расширение со знаком и определенно записывается полный RAX с 64-битным размером операнда, не оставляя их для неявного нулевого расширения. Хотел бы +1 к этому ответу, как только вы исправите эту ошибку, я думаю, вы точно определили путаницу OP между asm и машинным кодом.

Peter Cordes 31.10.2018 13:00

@PeterCordes: вы можете описать его как 2 разных 8-битных кода операции, или вы можете описать его как один 7-битный код операции, который имеет дополнительный параметр «направления», вставленный в (самый низкий) бит, или вы можете описать его как 32 разных 16 -битовые коды операций (по одному для каждого регистра, для каждого направления) или ... Все равно, независимо от того, как это кто-то описывает.

Brendan 31.10.2018 13:12

Это честно; Intel определяет это так, как я описал, но ваш взгляд на это тоже имеет смысл. Я предполагаю, что вы работаете над обновлением других пунктов, особенно последнего абзаца.

Peter Cordes 31.10.2018 13:21

@PeterCordes: Для кодировки, которую я использовал в примере, я просто поместил "mov rax, 1" в онлайн-ассемблер (в defuse.ca/online-x86-assembler.htm) и скопировал то, что он сказал. Ассемблер может выбрать разные способы кодирования одной и той же инструкции, и на самом деле не имеет большого значения, что используется в примере. Обратите внимание, что это может иметь практическое применение - например, Я знаю по крайней мере один ассемблер (a86 и a386), который использует его для борьбы с пиратством (поэтому автор ассемблера может сказать, использовался ли его ассемблер / не использовался, основываясь на том, какие кодировки были выбраны).

Brendan 31.10.2018 13:21

У вас получилась кодировка mov r/m64, sign_extended_imm32. Ваше описание неверно для этого, но идеально подходит для оптимизации, которую делают NASM и MASM, оптимизации его до mov eax, imm32

Peter Cordes 31.10.2018 13:24

@PeterCordes: А, теперь я понимаю, о чем вы говорите (извините, теперь исправлено!)

Brendan 31.10.2018 13:26

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