Pregunta

Soy un firme creyente en la idea de que una de las cosas más importantes que obtienes al aprender un nuevo idioma no es cómo usar un nuevo idioma, sino el conocimiento de los conceptos que obtienes de él. No estoy preguntando qué tan importante o útil crees que es Assembly, ni me importa si nunca lo uso en ninguno de mis proyectos reales.

Lo que quiero saber es qué conceptos de ensamblaje crees que son los más importantes para que lo sepa cualquier programador general. No tiene que estar directamente relacionado con el Ensamblaje, también puede ser algo que el programador típico que pasa todo el tiempo en lenguajes de nivel superior no entendería o daría por sentado, como el caché de la CPU.

¿Fue útil?

Solución

Creo que el lenguaje ensamblador puede enseñarte muchas cosas pequeñas, así como algunos conceptos grandes.

Enumeraré algunas cosas en las que puedo pensar aquí, pero no hay sustituto para ir y aprender y usar tanto x86 como un conjunto de instrucciones RISC.

Probablemente pienses que las operaciones de enteros son más rápidas. Si desea encontrar una raíz cuadrada entera de un entero (es decir, floor (sqrt (i))) es mejor usar una rutina de aproximación de solo enteros, ¿no?

No El coprocesador matemático (en x86) tiene una instrucción fsqrt . Convertir a flotar, tomar la raíz cuadrada y convertir a int de nuevo es más rápido que un algoritmo de todos los enteros.

Luego, hay cosas como acceder a la memoria que puede seguir, pero que no es apropiado, hasta que haya profundizado en el ensamblaje. Digamos que tenía una lista vinculada y que el primer elemento de la lista contiene una variable a la que tendrá que acceder con frecuencia. La lista se reordena raramente. Bueno, cada vez que necesite acceder a esa variable, debe cargar el puntero al primer elemento de la lista y luego usarlo, cargar la variable (asumiendo que no puede mantener la dirección de la variable en un registro entre usos) . Si en cambio almacenó la variable fuera de la lista, solo necesita una única operación de carga.

Por supuesto, guardar un par de ciclos aquí y generalmente no es importante en estos días. Pero si planea escribir un código que necesita ser rápido, este tipo de conocimiento puede aplicarse tanto con ensamblaje en línea como en general en otros idiomas.

¿Qué hay de llamar convenciones? (Algunos ensambladores se encargan de esto por usted: los programadores reales no los usan). ¿La persona que llama o la persona que llama limpian la pila? ¿Incluso usas la pila? Puede pasar valores en los registros, pero debido al conjunto de instrucciones divertidas x86, es mejor pasar ciertas cosas en ciertos registros. ¿Y qué registros se conservarán? Una cosa que los compiladores de C no pueden optimizar por sí mismos son las llamadas.

Hay pequeños trucos como PUSHing una dirección de retorno y luego JMPing en un procedimiento; Cuando el procedimiento vuelva, irá a la dirección PUSHed. Esta desviación de la forma habitual de pensar acerca de las llamadas a funciones es otro de esos "estados de iluminación". Si alguna vez diseñó un lenguaje de programación con características innovadoras, debería saber sobre cosas divertidas de las que es capaz el hardware.

Un conocimiento del lenguaje ensamblador le enseña cosas específicas de la arquitectura acerca de la seguridad informática. Cómo podría explotar los desbordamientos de búfer, o entrar en modo kernel, y cómo prevenir tales ataques.

Luego está la ubicuidad del código de auto-modificación, y como un problema relacionado, los mecanismos para cosas como las reubicaciones y la aplicación de parches al código (esto también requiere una investigación del código de la máquina).

Pero todas estas cosas necesitan el tipo correcto de mente. Si eres el tipo de persona que puede poner

while(x--)
{
  ...
}

para un buen uso una vez que aprenda lo que hace, pero le resultaría difícil averiguar qué hace por sí mismo, entonces el lenguaje ensamblador es probablemente una pérdida de tiempo.

Otros consejos

Registro de asignación y gestión

El ensamblaje le da una muy buena idea de cuántas variables (enteros de tamaño máquina-palabra) la CPU puede hacer malabares simultáneamente. Si puede dividir sus bucles de modo que involucren solo unas pocas variables temporales, todos ellos encajarán en los registros. Si no, su bucle se ejecutará lentamente a medida que las cosas se intercambien en la memoria.

Esto realmente me ha ayudado con mi código C Intento hacer todos los bucles ajustados y simples, con la menor cantidad posible de espaguetis.

x86 es tonto

Aprender varios lenguajes de ensamblaje me ha hecho darme cuenta de cuán escaso es el conjunto de instrucciones x86. ¿Instrucciones de longitud variable? ¿Tiempo difícil de predecir? ¿Modos de direccionamiento no ortogonales? Ugh.

El mundo sería mejor si todos ejecutáramos MIPS, creo, o incluso ARM o PowerPC :-) O, mejor dicho, si Intel / AMD tomara su experiencia en semiconductores y la usara para hacer multi-core, ultra-fast, ultra - Procese procesadores MIPS en lugar de procesadores x86 con todas esas cualidades de redención.

Es bueno saber el lenguaje ensamblador para obtener una mejor apreciación de cómo funciona la computadora " bajo el capó, " y ayuda cuando está depurando algo y todo lo que el depurador le puede dar es una lista de códigos de ensamblaje, que al menos le da la oportunidad de descubrir cuál podría ser el problema. Sin embargo, tratar de aplicar el conocimiento de bajo nivel a los lenguajes de programación de alto nivel, como tratar de aprovechar la forma en que la CPU almacena en caché las instrucciones y luego escribir el código de alto nivel no forzado para forzar al compilador a producir un código de máquina súper eficiente, es probablemente una señal de que está intentando micro-optimizar. En la mayoría de los casos, generalmente es mejor no intentar ser más astuto que el compilador, a menos que necesite la ganancia de rendimiento, en cuyo caso, también podría escribir esos bits en el ensamblaje de todos modos.

Por lo tanto, es bueno saber ensamblaje para comprender mejor cómo funcionan las cosas, pero el conocimiento adquirido no es necesariamente directamente aplicable a cómo se escribe el código en lenguajes de alto nivel. Sin embargo, en esa nota, encontré que aprender cómo funcionan las llamadas a funciones a nivel de código de ensamblaje (aprender sobre la pila y los registros relacionados, aprender cómo se pasan los parámetros en la pila, aprender cómo funciona el almacenamiento automático, etc.) problemas mucho más fáciles de entender que tuve en el código de nivel superior, como " fuera del espacio de pila " errores y " convención de llamada inválida " errores.

El concepto más importante es SIMD y su uso creativo. El uso adecuado de SIMD puede brindar enormes beneficios de rendimiento en una gran variedad de aplicaciones que van desde todo el procesamiento de cadenas hasta la manipulación de video y las matrices. Aquí es donde puede superar los incrementos de rendimiento 10x sobre el código C puro : esta es la razón por la que el ensamblaje sigue siendo útil más allá de la simple depuración.

Algunos ejemplos del proyecto en el que trabajo (todos los números son recuentos de ciclos de reloj en un Core 2):

DCT H.264 inverso 8 (transformada de frecuencia):

c: 1332
mmx: 187
sse2: 127

Compensación de movimiento Chroma 8x8 (filtro de interpolación bilineal):

c: 639
mmx: 144
sse2: 110
ssse3: 79

4 16x16 Operaciones de suma de diferencia absoluta (búsqueda de movimiento):

c: 3948
mmx: 278
sse2: 231
ssse3: 215

(sí, así es, ¡más de 18 veces más rápido que C!)

Error cuadrático medio de un bloque 16x16:

c: 1013
mmx: 193
sse2: 131

Varianza de un bloque 16x16:

c: 783
mmx: 171
sse2: 106

Memoria, registros, saltos, bucles, desplazamientos y las diversas operaciones que se pueden realizar en el ensamblador. No me pierdo los días de depurar mis programas de lenguaje de ensamblador, ¡fueron dolorosos! - Pero ciertamente me dio una buena base.

Olvidamos (o nunca supimos, tal vez) que todas estas cosas de pantalones de fantasía que usamos hoy (y que me encantan) se reducen a todas estas cosas al final.

Ahora, sin duda podemos tener una carrera productiva y lucrativa sin conocer al ensamblador, pero creo que es bueno saber estos conceptos.

Yo diría que el aprendizaje de la recursión y los bucles en ensamblaje me ha enseñado mucho. Me hizo entender el concepto subyacente de cómo el compilador / intérprete del lenguaje que estoy usando empuja las cosas en una pila y las saca de un salto cuando las necesita. También aprendí cómo explotar el desbordamiento de pila infame. (lo cual es sorprendentemente fácil en C con algunos comandos get y put).

Aparte de usar asm en situaciones cotidianas, no creo que usaría ninguno de los conceptos que me enseñaron en una asamblea.

Yo diría que los modos de direccionamiento son extremadamente importantes.

Mi alma mater llevó eso a un extremo, y como x86 no tenía suficientes, estudiamos todo en un simulador de PDP11 que debe haber tenido al menos 7 de ellos que recuerdo. En retrospectiva, esa fue una buena elección.

tiempo

ejecución rápida:

  • procesamiento paralelo
  • instrucciones simples
  • tablas de búsqueda
  • predicción de ramificación, canalización

rápido al acceso lento al almacenamiento:

  • registros
  • caché, y varios niveles de caché
  • pila de memoria y pila
  • memoria virtual
  • E / S externa

Hoy en día, x86 asm no es una línea directa a las entrañas de la CPU, sino más bien una API. Los códigos de operación del ensamblador que usted escribe se compilan en un conjunto de instrucciones completamente diferente, se reorganizan, se vuelven a escribir, se arreglan y, por lo general, no se reconocen.

Por lo tanto, no es como si el ensamblador de aprendizaje te da una idea fundamental de lo que está sucediendo dentro de la CPU. En mi humilde opinión, más importante que aprender el ensamblador es obtener una buena comprensión de cómo funcionan la CPU de destino y la jerarquía de memoria.

Esta serie de artículos cubre este último tema con bastante detalle.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top