pop eip
- не настоящая инструкция x86. Никакой ассемблер не будет ее собирать, AFAIK.
Это псевдокод для , объясняющий , что делает ret
.См. Раздел «Эксплуатация» в руководстве .В частности, нормальный "рядом" ret
;far jmp / call / ret в основном не используются в "нормальном" 32-битном коде.
ret
имеет свой собственный код операции, отличный от любой кодировки для pop
, и x86 также решает дать емуОтдельная мнемоника.Это был бы действительный дизайн для pop eip
, который также был бы принят в качестве другого имени для кода операции 0xc3
.x86 имеет мнемонику mov
, перегруженную для многих различных кодов операций, включая mov
в / из управляющих регистров , mov
в / из регистры отладки , а также стандарт mov
между целочисленными регистрами и / или памятью или непосредственно.(Однако в этой «стандартной» форме mov
также есть несколько различных кодов операций.)
Но это было бы немного странно, потому что push eip
не существует, за исключением call +0
, которыйимеет побочный эффект производительности - скачок.
EIP не является одним из 8 целочисленных регистров общего назначения, поэтому обычные кодировки pop
не могут кодировать ret
.Это одна из причин, по которой ret
нужен собственный код операции, и поэтому имеет смысл иметь отдельную мнемонику в источнике asm.Инструкции x86 кодируют регистры как 3-битные числа или, необязательно, 4-битные на x86-64.Или как неявный источник или назначение, например EDX: EAX для mul
или div
, или pushf
неявно читает EFLAGS: это просто подразумевается этим кодом операции без каких-либо битов, которые конкретно означают EFLAGS.
ret
не волшебство: все, что он делает, это подбрасывает стек и использует результат в качестве цели прыжка.Программист должен убедиться, что ESP указывает на адрес, на который вы хотите перейти, обычно это обратный адрес.
Некоторые новички не понимают этого и думают, что ret
волшебным образом вернется к последнему call
, поэтому они не устанавливают связь между ошибками на ret
и их кодом, запутывающим стек.
Я определенно написал что-то вроде "ret
- это имя, которое мы используемна x86 для pop eip
"в SO вопросы и ответы много раз.
Интересный факт: на 32-битном ARM счетчик программы равен одному из 16 целочисленных регистров,r15
, так что вы действительно можете pop {r4, pc}
восстановить сохраненный R4 и вставить сохраненный lr
(регистр связи = обратный адрес) в счетчик программ все в одной инструкции.Таким образом, ARM буквально может сделать эквивалент pop eip
с тем же кодом операции, который он использует для получения целочисленных регистров общего назначения.
esp вырос на 4, а eip увеличился на 20
Да, я думаю C3 ret
или C2 ret 0
- это только 2 опкода, которые могут сделать это, и оба используют мнемонику ret
.
ЕслиEIP вырос на 15 или меньше, его может объяснить длинная кодировка add esp, 4
или pop eax
, например, с несколькими избыточными префиксами rep
и / или fs
и кодировкой imm32
для немедленной 4
.
x86 инструкции могут быть длиной не более 15 байтов;если декодирование не достигает конца инструкции до 15 байт, процессор принимает исключение #UD
, как и для других недопустимых инструкций.Таким образом, изменение EIP на 20 байтов одной инструкцией возможно только с помощью перехода.И единственный скачок, который увеличивается ESP - ret
;jmp / jcc оставляют его без изменений, call
выдвигает обратный адрес.
iret
почти возможно, но он выдает CS:IP
и значение FLAGS: вы не можете получить его для выгрузки только 4 байта.(Особенно в 32-битном режиме.)
sysret
не изменяет ESP, и может использоваться только ядром (кольцо 0).sysexit
устанавливает RSP из RCX и RIP = RDX, но я уверен, что это не тот ответ, который они искали.: P