2008-10-24 11 views
69

Voy a través de MSIL y me doy cuenta de que hay un montón de instrucciones nop. El artículo de MSDN dice que no toman ninguna medida y se utilizan para llenar el espacio si el código de operación está parchado. Se usan mucho más en compilaciones de depuración que versiones de lanzamiento. Sé que este tipo de declaraciones se utilizan en los lenguajes ensambladores para garantizar que un código de operación se ajuste a un límite de palabras, pero ¿por qué es necesario en MSIL?¿Cuál es el propósito del opcode de nop?

+18

Existe confusión masiva en estas respuestas entre las instrucciones MSIL nop emitidas por el compilador de lenguaje en el ensamblado y las instrucciones x86 nop (en esa plataforma) emitidas por el compilador JIT cuando se ejecuta el ensamblado. [De hecho, la respuesta aceptada es acerca de x86 nudos, y no tiene relación con MSIL.] Idealmente, esta pregunta debería dividirse en 2 preguntas diferentes: propósito de MSIL :: nop? y el propósito de la plataforma nativa nop? –

Respuesta

88

NOP sirven para varios propósitos:

  • permiten al depurador para colocar un punto de interrupción en una línea, incluso si se combina con otros en el código generado.
  • Permite al cargador aplicar un parche de salto con un desplazamiento de objetivo de diferente tamaño.
  • Permite que un bloque de código se alinee en un límite particular, lo que puede ser bueno para el almacenamiento en caché.
  • Permite el enlace incremental para sobrescribir trozos de código con una llamada a una nueva sección sin tener que preocuparse por la función general que cambia el tamaño.
+0

De [Wikipedia] (https://en.wikipedia.org/wiki/NOP): "Un NOP es el más comúnmente utilizado para fines de temporización, para forzar la alineación de la memoria, evitar riesgos, ocupar una ranura de retardo de bifurcación, anular una instrucción existente como un salto o como un marcador de posición para ser reemplazada por instrucciones activas más adelante en el desarrollo del programa (o para reemplazar las instrucciones eliminadas cuando la refactorización sería problemática o consumiría mucho tiempo). En algunos casos, un NOP puede tener efectos secundarios menores, por ejemplo, en la serie de procesadores Motorola 68000, el código de operación NOP provoca una sincronización de la tubería ". – mbomb007

8

Proporciona una oportunidad para los marcadores basados ​​en línea (por ejemplo, puntos de interrupción) en el código donde una versión de lanzamiento no emitiría ninguno.

+0

¿Los puntos de interrupción deben estar en un nop? ¿Por qué no simplemente poner un punto de interrupción en el código de operación regular? –

+4

una gran cantidad de códigos de operación regulares optimizados en versiones de lanzamiento. Eso estropearía tus puntos de ruptura a menos que hubiera un marcador de posición allí donde los puntos de interrupción aún apuntaran a – Jimmy

+1

En las compilaciones de depuración, también se usan para proporcionar una instrucción para interrumpir donde el código no tiene instrucciones. Apertura de llaves, por ejemplo. –

3

Un uso clásico para ellos es para que su depurador siempre pueda asociar una línea de código fuente con una instrucción IL.

+0

¿No podría suceder eso de todos modos? –

+0

Dado que msil está compilado JIT cuando se ejecuta, es posible perder esa asignación (por ejemplo, la instrucción nativa no tiene instrucción MSIL única). Los NOP se utilizan como mecanismo de comunicación desde el compilador de lenguaje hasta el compilador JIT para preservar dicho mapeo. –

4

¡Amigo! ¡No-operativo es increíble! Es una instrucción que no hace más que consumir tiempo. En las oscuras edades oscuras lo usarías para hacer microajustes en el tiempo en bucles críticos o, más importante aún, como relleno en el código de auto modificación.

+0

Entiendo su uso cuando se ejecuta directamente en el hardware, pero MSIL está JIT. –

+0

MSIL solo está JIT en sistemas que tienen JIT. MSIL no exige JIT. – plinth

1

Permiten que el enlazador reemplace una instrucción más larga (típicamente salto largo) por una más corta (salto corto). El NOP toma el espacio extra: el código no se podía mover ya que evitaría que otros saltos funcionaran. Esto ocurre en tiempo de enlace, por lo que el compilador no puede saber si un salto largo o corto sería apropiado.

Al menos, ese es uno de sus usos tradicionales.

3

Podrían estar utilizándolos para admitir edit-and-continue durante la depuración. Proporciona al depurador espacio para trabajar para reemplazar el código antiguo por nuevo sin cambiar los desplazamientos, etc.

+4

Implementé el soporte del depurador en VS para editar y continuar (no implementé el CLR ni las partes del compilador). Los Nops son parte de la historia para garantizar asignaciones correctas de la versión anterior a la nueva de un método (específicamente en los casos de saltos del código de manejo de la excepción). Sin embargo, la sustitución de MSIL se realiza en función de todas las funciones. Para el código administrado CLR no es necesario 'dejar espacio' en el msil para lograr esa parte. Lo que dices aquí es correcto con respecto a Editar nativo y continuar. –

1

No es una respuesta a su pregunta específica, pero en los viejos tiempos podía usar un NOP para llenar un branch delay slot , si no logras llenarlo con una instrucción útil.

1

¿Los compiladores .NET alinean la salida de MSIL? Me imagino que podría ser útil para acelerar el acceso a la IL ... Además, tengo entendido que está diseñado para ser portátil y que se requieren accesos alineados en algunas otras plataformas de hardware.

2

En la escena de descifrado de software, un método clásico para desbloquear una aplicación sería parchar con un NOP la línea que busca la clave o registro o período de tiempo o lo que sea, así no haría nada y simplemente continuar iniciando la aplicación como si está registrado

+4

Estoy bastante seguro de que las instrucciones no operativas no fueron inventadas para ayudar a las personas a piratear software :-) –

2

También he visto NOP en el código que se modifica a sí mismo para ocultar lo que hace como marcador de posición (protección de copia anterior).

1

El primer ensamblaje que aprendí fue SPARC, así que estoy familiarizado con la ranura de retardo de bifurcación, si no puede completarla con otra instrucción, generalmente la instrucción que iba a colocar encima de la instrucción de bifurcación o incrementar un contador en bucles, usa un NOP.

No estoy familiarizado con las grietas, pero creo que es común sobrescribir la pila utilizando NOP, por lo que no tiene que calcular exactamente dónde comienza su función maliciosa.

4

También puede hacer que el código se ejecute más rápido, cuando se optimiza para los procesadores o arquitecturas específicas:

Procesadores durante mucho tiempo emplear múltiples tuberías que funcionan más o menos en paralelo, por lo que dos de instrucción independiente puede exceuted al mismo tiempo. En un procesador simple con dos tuberías, el primero puede admitir todas las instrucciones, mientras que el segundo solo admite un subconjunto. Además, hay algunas paradas entre las tuberías cuando uno tiene que esperar el resultado de una instrucción previa que aún no ha finalizado.

En estas circunstancias, un dedicado nop puede obligar a la siguiente instrucción en una tubería específica (la primera, o no la primera), y mejorar el emparejamiento de las instrucciones siguientes para que el costo de la nop es más que amortizado

3

Nop es esencial en la carga de los exploits de desbordamiento de búfer.

3

Como dijo ddaa, los nops le permiten tener en cuenta la varianza en la pila, de modo que cuando sobrescribe la dirección de retorno salta al trineo nop (una gran cantidad de nops seguidos) y luego acierta el código ejecutable correctamente. que saltar a algún byte en la instrucción que no es el comienzo.

9

Así es como NOP son utilizados por la depuración:

Nops son utilizados por los compiladores de lenguajes (C#, VB, etc.) para definir puntos de secuencia implícitos. Éstos le dicen al compilador JIT dónde asegurarse de que las instrucciones de la máquina se puedan mapear a las instrucciones IL.

Entrada del blog de Rick Byer en DebuggingModes.IgnoreSymbolStoreSequencePoints, explica algunos de los detalles.

C# también coloca Nops después de las instrucciones de la llamada para que la ubicación del sitio de retorno en la fuente sea la llamada en lugar de la línea después de la llamada.

1

Utilicé NOP para ajustar automágicamente la latencia acumulada después de ingresar un ISR. Muy útil para clavar el tiempo muerto.

2

Un uso algo poco ortodoxo es NOP-Slides, que se utiliza en exploits de desbordamiento de búfer.

+0

estaba buscando esto :) –

+0

Corrija su enlace, no está funcionando, por favor siempre asegúrese de enviar el enlace al archivo web, ya que no dan 404 no encontrados. –

3

50 años demasiado tarde pero bueno.

Nop son útiles si está escribiendo código de ensamblaje a mano. Si tuviera que eliminar el código, podría anotar los códigos de operación anteriores.

Similarmente, podría insertar un nuevo código al sobrescribir algún código de operación y saltar a otro lugar. Allí colocas los códigos de operación sobrescritos e insertas tu nuevo código. Cuando estás listo, saltas hacia atrás.

A veces tenía que usar las herramientas que estaban disponibles. En algunos casos, este fue solo un editor de código de máquina muy básico.

Hoy en día, con los compiladores las técnicas ya no tienen sentido.

2

En un procesador en el que trabajé recientemente (durante cuatro años) NOP se usó para asegurarse de que la operación anterior finalizara antes de que comenzara la siguiente operación. Por ejemplo:

valor de carga para registrar (se tarda 8 ciclos) nop 8 añadir 1 en el registro

Esto se aseguró de registro tenía el valor correcto antes de la operación de suma.

Otro uso era completar unidades de ejecución, como los vectores de interrupción que tenían que ser de cierto tamaño (32 bytes) porque la dirección para vector0 era, digamos 0, para el vector 1 0x20 y así sucesivamente, por lo que el compilador puso NOPs allí si es necesario.

Cuestiones relacionadas