¿Qué significa "rep; nop;" en el ensamblaje x86? ¿Es lo mismo que la instrucción de "pausa"?
- ¿Qué significa
rep; nop
? - ¿Es lo mismo que
pause
la instrucción? - ¿Es lo mismo que
rep nop
(sin el punto y coma)? - ¿Cuál es la diferencia con la instrucción simple
nop
? - ¿Se comporta de manera diferente en los procesadores AMD e Intel?
- (bonus) ¿Dónde está la documentación oficial para estas instrucciones?
Motivación para esta pregunta
Después de alguna discusión en los comentarios de otro pregunta , me di cuenta de que no se lo que rep; nop;
significa en el ensamblaje x86 (o x86-64). Y tampoco pude encontrar una buena explicación en la web.
Sé que rep
es un prefijo que significa "repetir la siguiente instrucción cx
veces" (o al menos lo era, en el antiguo ensamblado x86 de 16 bits). De acuerdo con esta tabla de resumen en Wikipedia , parece que rep
solo se puede usar con movs
, stos
, cmps
, lods
, scas
(pero tal vez esta limitación se eliminó en los procesadores más nuevos). Por lo tanto, yo pensaría que rep nop
(sin punto y coma) repetiría una operación nop
cx
veces.
Sin embargo, después de buscar más, me confundí aún más. Parece que rep; nop
y pause
mapea exactamente el mismo opcode , y pause
tiene un comportamiento un poco diferente que solo nop
. Algunos correos antiguos de 2005 decían cosas diferentes: {[41]]}
- "trate de no quemar demasiado poder"
- "es equivalente a' nop ' solo con 2 bytes codificación."
- "es magia en inteligencia. Es como 'nop pero deja que el otro hermano de HT corra'"
- "es una pausa en intel y un relleno rápido en Athlon"
Con estas diferentes opiniones, no podía entender el significado correcto.
Se está utilizando en el núcleo Linux (tanto en i386 y x86_64), junto con este comentario: /* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */
También se está utilizando en BeRTOS, con el mismo comentario.
2 answers
rep; nop
es de hecho lo mismo que la instrucción pause
(opcode F390
). Podría usarse para ensambladores que aún no soportan la instrucción pause
. En procesadores anteriores, esto simplemente no hacía nada, al igual que nop
pero en dos bytes. En los nuevos procesadores que admiten hyperthreading, se usa como una pista al procesador de que está ejecutando un spinloop para aumentar el rendimiento. De Referencia de instrucciones de Intel :
Mejora el rendimiento de los bucles spin-wait. Cuando al ejecutar un "bucle spin-wait", un procesador Pentium 4 o Intel Xeon sufre una grave penalización de rendimiento al salir del bucle porque detecta una posible violación del orden de memoria. La instrucción PAUSE proporciona una pista al procesador de que la secuencia de código es un bucle spin-wait. El procesador utiliza esta sugerencia para evitar la violación del orden de la memoria en la mayoría de las situaciones, lo que mejora en gran medida el rendimiento del procesador. Por esta razón, se recomienda que se coloque una instrucción de PAUSA en todos los spin-wait bucle.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-08 10:07:10
Los prefijos que no se aplican a una instrucción son ignorados. Sin embargo, las CPU futuras pueden usar esa secuencia de bytes para codificar una nueva instrucción. (sí, el espacio del opcode x86 es tan limitado que hacen cosas locas como esta, y sí, hace que los decodificadores sean complicados.)
En este caso, significa que puede usar pause
en spinloops sin romper hacia atrás compat. Las CPU antiguas que no conocen pause
lo decodificarán como un NOP sin daño. En las nuevas CPU, obtienes el beneficio de ahorro de energía / compatibilidad con HT, y evitar la especulación errónea de ordenar la memoria cuando la memoria en la que estás girando cambia y estás dejando el bucle de giro.
Enlaces a los manuales de Intel y toneladas de otras cosas buenas en la página de información wiki de etiquetas x86: https://stackoverflow.com/tags/x86/info
Otro caso de un prefijo sin sentido rep
convirtiéndose en una nueva instrucción en nuevas CPU: lzcnt
es F3 0F BD /r
. En CPU que no soportan esa instrucción (falta el LZCNT feature flag en su CPUID), se decodifica como rep bsr
, que se ejecuta igual que bsr
. Así que en CPU antiguas, produce 32 - expected_result
, y es indefinido cuando la entrada era cero.
Un caso de un prefijo rep
sin sentido que probablemente nunca decodificará de manera diferente: rep ret
es utilizado por defecto por gcc cuando se dirige a CPU "genéricas" (es decir, no se dirige a una CPU específica con -march
o -mtune
, y no se dirige a AMD K8 o K10.) Pasarán décadas antes de que alguien pueda hacer una CPU que decodifique rep ret
como cualquier otra cosa que no sea ret
, porque está presente en la mayoría de los binarios en la mayoría de las distribuciones de Linux. Ver ¿Qué significa `rep ret`?
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-17 18:51:58