assembly - Preguntas sobre el diseño de sintaxis AT&T x86
x86 assembly (4)
- ¿Puede alguien explicarme por qué cada constante en la sintaxis de AT&T tiene un ''$'' delante?
- ¿Por qué todos los registros tienen un ''%''?
- ¿Es esto solo otro intento para que yo haga un montón de escritura?
- Además, ¿soy el único que encuentra que
16(%esp)
realmente poco intuitivo en comparación con[esp+16]
? - Sé que se compila de la misma manera, pero ¿por qué alguien querría escribir muchos ''$'' y ''%'' s sin necesidad de hacerlo? - ¿Por qué GNU eligió esta sintaxis como la predeterminada?
- Otra cosa, ¿por qué cada instrucción en la sintaxis de at & t está precedida por un: l? - Sé que es para el tamaño de los operandos, sin embargo, ¿por qué no dejar que el ensamblador lo descubra? (¿Querría alguna vez hacer un movimiento en operandos que no son de ese tamaño?)
- Lo último: ¿por qué se invierten los argumentos mov?
¿No es más lógico que:
eax = 5
mov eax, 5
donde como at & t es:
mov 5, eax
5 = a (? wait what ?)
Nota: No estoy tratando de troll. Simplemente no entiendo las elecciones de diseño que hicieron y estoy tratando de saber por qué hicieron lo que hicieron.
1, 2, 3 y 5: la notación es algo redundante, pero me parece una buena cosa cuando se desarrolla en ensamblaje. La redundancia ayuda a la lectura. El punto sobre "dejar que el ensamblador lo descubra" se convierte fácilmente en "dejar que el programador que lee el código lo resuelva", y no me gusta cuando soy el que hace la lectura. La programación no es una tarea de solo escritura; incluso el programador mismo debe leer su propio código, y la redundancia de sintaxis ayuda bastante.
Otro punto es que ''%'' y ''$'' significan que se pueden agregar nuevos registros sin romper la compatibilidad con versiones anteriores: no hay problema en agregar, por ejemplo, un registro llamado xmm4
, ya que se escribirá como %xmm4
, que no se puede confundir con una variable llamada xmm4
que se escribiría sin un ''%''.
En cuanto a la cantidad de escritura: normalmente, cuando se programa en ensamblaje, el cuello de botella es el cerebro, no la mano. Si el ''$'' y el ''%'' lo reducen, entonces está pensando mucho más rápido de lo que generalmente se considera factible para un ser humano o, más probablemente, su tarea en cuestión es demasiado mecánica y no debe hacerse en montaje; debe dejarse a un generador de código automático, algo coloquialmente conocido como "compilador de C".
El sufijo ''l'' se agregó para manejar algunas situaciones donde el ensamblador "no puede" resolverlo. Por ejemplo, este código:
mov [esp], 10
es ambiguo, porque no indica si desea escribir un byte de valor 10 o una palabra de 32 bits con el mismo valor numérico. La sintaxis de Intel entonces llama a:
mov byte ptr [esp], 10
que es bastante feo, cuando lo piensas. La gente de AT&T quería hacer algo más racional, por lo que se les ocurrió:
movb $10, (%esp)
y prefirieron ser sistemáticos y tener el sufijo ''b'' (o ''l'' o ''w'') en todas partes . Tenga en cuenta que el sufijo no siempre es necesario . Por ejemplo, puedes escribir:
mov %al, (%ebx)
y deje que el ensamblador GNU "descubra" que, dado que está hablando de ''% al'', el movimiento es para un solo byte. Realmente funciona ! Sin embargo, aún me parece mejor especificar el tamaño (realmente ayuda al lector, y el programador mismo es el primer y más importante lector de su propio código).
Para la "inversión": es al revés. La sintaxis de Intel imita lo que ocurre en C, en el que los valores se calculan a la derecha y luego se escriben en lo que está a la izquierda. Por lo tanto, la escritura va de derecha a izquierda, en la dirección "inversa", teniendo en cuenta que la lectura va de izquierda a derecha. La sintaxis de AT&T vuelve a la dirección "normal". Al menos así lo consideraron; Ya que decidieron usar su propia sintaxis de todos modos, pensaron que podían usar los operandos en lo que consideraban "el orden correcto". Esto es principalmente una convención, pero no una ilógica. La convención de C imita la notación matemática, excepto que las matemáticas se refieren a la definición de valores ("sea x el valor 5") y no a la asignación de valores ("escribimos el valor 5 en una ranura llamada ''x''"). La elección de AT&T tiene sentido. Es confuso solo cuando está convirtiendo el código C en un ensamblaje, una tarea que generalmente se debe dejar en un compilador de C.
La última parte de su pregunta 5 es interesante, desde un punto de vista histórico. Las herramientas GNU para x86 siguieron la sintaxis de AT&T porque en ese momento intentaban afianzarse en el mundo Unix ("GNU" significa "GNU no es Unix") y competían con las herramientas Unix; Unix estaba bajo el control de AT&T. Esto es antes de los días de Linux o incluso de Windows 3.0; PC fueron sistemas de 16 bits. Unix usó la sintaxis de AT&T, por lo tanto, GNU usó la sintaxis de AT&T.
La buena pregunta es entonces: ¿por qué a AT&T le pareció inteligente inventar su propia sintaxis? Como se describió anteriormente, tenían algunas razones que no carecían de mérito. El costo de usar su propia sintaxis, por supuesto, es que limita la interoperabilidad. En aquellos días, un compilador o ensamblador de C no tenía ningún sentido como herramienta separada: en un sistema Unix, estaban destinados a ser proporcionados por el proveedor del sistema operativo. Además, Intel no era un jugador importante en el mundo de Unix; Los sistemas grandes usaban en su mayoría VAX o Motorola 680x0 derivados. Nadie se había dado cuenta de que la PC MS-Dos se convertiría, veinte años más tarde, en la arquitectura dominante en los mundos de escritorio y servidores.
1-2, 5: Probablemente eligieron prefijar los registros y eso para facilitar el análisis; Usted sabe directamente en el primer carácter qué tipo de token es.
4: No.
6: Nuevamente, probablemente sea más fácil para el analizador averiguar qué instrucciones emitir.
7: En realidad, esto tiene más sentido en un significado gramatical, mover qué a dónde . Tal vez la instrucción mov debería ser una instrucción ld .
No me malinterpretes, creo que la sintaxis de AT&T es horrible.
La razón por la que la sintaxis de AT&T invierte el orden de los operandos en comparación con Intel es muy probable porque el PDP-11, en el que se desarrolló originalmente Unix, usa el mismo orden de operandos.
Intel y DEC simplemente eligieron órdenes opuestas.
La sintaxis AT&T del ensamblador GNU rastrea sus orígenes al ensamblador 1 de Unix, que a su vez tomó su sintaxis de entrada principalmente desde el ensamblador PAL-11 PDP-11 (ca. 1970).
¿Puede alguien explicarme por qué cada constante en la sintaxis de AT&T tiene un ''$'' delante?
Permite distinguir constantes inmediatas de direcciones de memoria. La sintaxis de Intel lo hace al revés, con referencias de memoria como [foo]
.
Incidentalmente, MASM (el ensamblador de Microsoft) no necesita una distinción en el nivel de sintaxis, ya que puede indicar si el operando es una constante simbólica o una etiqueta. Otros ensambladores para x86 evitan activamente tales conjeturas, ya que pueden confundir a los lectores, por ejemplo: TASM en modo IDEAL (advierte sobre referencias de memoria que no están entre paréntesis), nasm, fasm.
PAL-11 usó #
para el modo de direccionamiento inmediato , donde el operando siguió la instrucción. Una constante sin #
significaba el modo de direccionamiento relativo , donde una dirección relativa seguía la instrucción.
Unix utilizó la misma sintaxis para los modos de direccionamiento que los ensambladores de DEC, con *
lugar de @
, y $
lugar de #
, ya que aparentemente @
y #
eran inconvenientes para el tipo 2 .
¿Por qué todos los registros tienen un ''%''?
En PAL-11, los registros se definieron como R0 =% 0, R1 =% 1, ... con R6 también se conoce como SP, y R7 también se conoce como PC. El macro-ensamblador DEC MACRO-11 permitió referirse a registros como %x
, donde x
podría ser una expresión arbitraria, por ejemplo, %3+1
referido a %4
.
¿Es esto solo otro intento para que yo haga un montón de escritura?
No
Además, ¿soy el único que encuentra que 16 (% esp) es realmente poco intuitivo en comparación con [esp + 16]?
Esto proviene del modo de direccionamiento de índice PDP-11, donde se forma una dirección de memoria sumando el contenido de un registro y una palabra de índice siguiendo la instrucción.
Sé que se compila de la misma manera, pero ¿por qué alguien querría escribir muchos ''$'' y ''%'' s sin necesidad de hacerlo? - ¿Por qué GNU eligió esta sintaxis como la predeterminada?
Procedía del PDP-11.
Otra cosa, ¿por qué cada instrucción en la sintaxis de at & t está precedida por un: l? - Sé que es para el tamaño de los operandos, sin embargo, ¿por qué no dejar que el ensamblador lo descubra? (¿Querría alguna vez hacer un movimiento en operandos que no son de ese tamaño?)
El gas generalmente puede resolverlo. Otros ensambladores también necesitan ayuda en casos particulares.
El PDP-11 usaría b
para instrucciones de bytes, por ejemplo: CLR
vs CLRB
. Otros sufijos aparecieron en VAX-11: l
para long, w
for word, f
para float, d
para double, q
para quad-word, ...
Last thing: why are the mov arguments inverted?
Podría decirse que, dado que el PDP-11 es anterior a los microprocesadores Intel, es al revés.
- Según la página de información del gas, a través del ensamblador BSD 4.2.
- Manual de referencia del ensamblador Unix §8.1 - Dennis M. Ritchie