Можно ли выполнить инструкцию «PUSH», используя другие инструкции? - PullRequest
3 голосов
/ 12 марта 2020

В настоящее время мне кажется, что единственная причина, по которой у нас есть такие инструкции, как «Push», заключается в замене нескольких команд MOV и арифметических c одной инструкцией.

Есть ли что-нибудь, что «НАЖМИТЕ» делает, что не может быть достигнуто более примитивными инструкциями?

Является ли «PUSH» просто Mnemoni c, который компилируется в несколько инструкций машинного кода?

1 Ответ

5 голосов
/ 12 марта 2020

Pu sh - это инструкция реальной машины (https://www.felixcloutier.com/x86/push) , а не , просто макрос / псевдоинструкция на ассемблере. Например, push rax имеет однобайтовую кодировку 0x50.

Но да, вы можете эмулировать ее, используя другие инструкции, такие как sub rsp, 8 и mov store. ( Это нормально для машины CIS C, такой как x86! ). Например, см. Какова функция команд pu sh / pop, используемых в регистрах в сборке x86?

Чтобы точно подражать (без изменения флагов), вы используете LEA вместо ADD / SUB.

  lea   rsp, [rsp-8]
  mov   qword [rsp], 123      ; push 123 in 64-bit mode

Есть ли что-нибудь, что «PUSH» делает, что не может быть выполнено более примитивным инструкции?

Ничего существенного, кроме эффективности и размера кода.

Отдельные инструкции - это atomi c wrt. прерывания - они либо случаются, либо нет. Это обычно совершенно не имеет значения; асинхронные прерывания обычно не проверяют содержимое стека / регистра кода, который был прерван.

PU SH может выполнить работу за один байт машинного кода для передачи одного регистра, или 2 байт для небольшого немедленного. Последовательность из нескольких инструкций намного больше. Архитектор ISA 8086 был очень сосредоточен на том, чтобы сделать возможным малый размер кода, поэтому да вполне нормально иметь инструкцию, которая заменяет пару более длинных инструкций одной короткой. например, у нас есть not вместо необходимость использовать xor reg, -1 и inc вместо add reg, 1. (Хотя, опять-таки, оба имеют разную семантику FLAGS, при этом НЕ оставляя флаги нетронутыми, а INC / DE C оставляя CF нетронутыми.) Не говоря уже о всех других особых кодировках x86, таких как 1-байтовые кодировки для xchg-with- [ е / г] ах. См. https://codegolf.stackexchange.com/questions/132981/tips-for-golfing-in-x86-x64-machine-code

Также эффективность: PU SH декодирует до одного UOP (в объединенной области) на процессорах Pentium-M и более поздних, благодаря стековому механизму, который обрабатывает неявные использует указатель стека такими инструкциями, как push / pop и call / ret. 2 отдельные инструкции, конечно, декодируют как минимум до 2 мопов. (За исключением особого случая макро-слияния test / cmp + J CC).

На древнем P5 Pentium эмуляция pu sh с отдельными инструкциями ALU и mov была фактически победой - раньше Процессоры PPro не знали, как разбить сложные инструкции CIS C на отдельные мопы, а сложные инструкции не могли соединиться в конвейере заказов двойного выпуска P5. (См. Руководство по микроарху Агнера Фога .) Главным преимуществом здесь было то, что можно было смешивать другие команды, которые могли быть спарены, и делать только один большой sub, а затем просто mov хранилища вместо нескольких изменяет указатель стека.

Это также относится к раннему семейству P6 до механизма стека. G CC с -march=pentium3, например, будет стремиться избежать push и просто сделать одну большую настройку для ESP.

...