assembly x86 x86-64 machine-code addressing-mode

assembly - rbp no permitido como base SIB?



x86 x86-64 (1)

Soy bastante nuevo en la codificación binaria x86-64. Estoy tratando de arreglar un viejo código "ensamblador".

De todos modos, estoy tratando de hacer algo como esto (sintaxis de Intel):

mov [rbp+rcx], al

El ensamblador está generando actualmente esto:

88 04 0D

pero eso no parece ser una instrucción válida. Si cambio la base en el byte SIB de rbp a algún otro registro, funciona bien. Otra forma de hacerlo funcionar es agregar un desplazamiento de un byte de cero ( 88 44 0D 00 ). Esto parece suceder con otros códigos de operación similares.

¿Por qué no puedo usar rbp allí con mod=00 ?


La codificación que significaría que rbp es un código de escape para ningún registro base (solo un disp32 en SIB o relativo a RIP rel32 en ModRM). La mayoría de los ensambladores ensamblan [rbp] en [rbp + disp8=0] .

Ya que no es necesario escalar, use [rcx + rbp] para evitar necesitar un disp8 = 0, porque rbp puede ser un índice.

(SS y DS siempre son equivalentes en modo largo, por lo que no importa que base = RBP implique SS, mientras que base = RCX implica usar el segmento DS).

Modo de direccionamiento ModRM x86 / x86-64 que codifica casos especiales

(de una respuesta que escribí en ¿Por qué los rbp y rsp se denominan registros de propósito general? ). Esta pregunta parece ser el lugar perfecto para copiar o trasplantar esta sección.

rbp / r13 no puede ser un registro base sin desplazamiento : esa codificación significa en cambio: (en ModRM) rel32 (relativo a RIP), o (en SIB) disp32 sin registro base. ( r13 usa los mismos 3 bits en ModRM / SIB, por lo que esta opción simplifica la decodificación al no hacer que el decodificador de longitud de instrucción mire el bit REX.B para obtener el cuarto bit de registro de base). [r13] ensambla a [r13 + disp8=0] . [r13+rdx] ensambla a [rdx+r13] (evitando el problema intercambiando base / índice cuando esa es una opción).

rsp / r12 como registro base siempre necesita un byte SIB . (La codificación ModR / M de base = RSP es un código de escape para señalar un byte SIB, y nuevamente, más del decodificador tendría que preocuparse por el prefijo REX si r12 se manejó de manera diferente).

rsp no puede ser un registro de índice . Esto hace posible codificar [rsp] , que es más útil que [rsp + rsp] . (Intel podría haber diseñado las codificaciones ModRM / SIB para los modos de direccionamiento de 32 bits (nuevo en 386), por lo que SIB sin índice solo era posible con base = ESP. Eso haría que [eax + esp*4] sea ​​posible y solo excluir [esp + esp*1/2/4/8] . Pero eso no es útil, por lo que simplificaron el hardware al hacer que el índice = ESP sea el código sin índice independientemente de la base. Esto permite dos formas redundantes de codificar cualquier base o Modo de direccionamiento base + disp: con o sin un SIB.)

r12 puede ser un registro de índice . A diferencia de los otros casos, esto no afecta la decodificación de longitud de instrucción. Además, no se puede solucionar con una codificación más larga como en los otros casos. AMD quería que el registro de AMD64 fuera lo más ortogonal posible, por lo que tiene sentido que gastarían unos cuantos transistores adicionales para verificar REX.X como parte de la decodificación índice / no índice. Por ejemplo, [rsp + r12*4] requiere index = r12, por lo que tener r12 no tiene un propósito general, haría de AMD64 un objetivo peor para el compilador.

0: 41 8b 03 mov eax,DWORD PTR [r11] 3: 41 8b 04 24 mov eax,DWORD PTR [r12] # needs a SIB like RSP 7: 41 8b 45 00 mov eax,DWORD PTR [r13+0x0] # needs a disp8 like RBP b: 41 8b 06 mov eax,DWORD PTR [r14] e: 41 8b 07 mov eax,DWORD PTR [r15] 11: 43 8b 04 e3 mov eax,DWORD PTR [r11+r12*8] # *can* be an index

Todo esto se aplica también a los modos de direccionamiento de 32 bits; la codificación es idéntica, excepto que no hay codificación relativa a EIP, solo dos formas redundantes de codificar disp32 sin base.

Consulte también https://wiki.osdev.org/X86-64_Instruction_Encoding#32.2F64-bit_addressing_2 para ver tablas como las del manual vol.2 de Intel.

Esto parece suceder con otros códigos de operación similares.

La codificación ModRM de los operandos r / m es siempre la misma. Algunos códigos de operación requieren un operando de registro y otros requieren memoria, pero el desplazamiento opcional opcional de ModRM + SIB + se corrige para que el mismo hardware pueda decodificarlo independientemente de la instrucción.

Hay algunos mov al/ax/eax/rax, [qword absolute_address] raros como mov al/ax/eax/rax, [qword absolute_address] que no usan la codificación ModRM para sus operandos, pero cualquiera que sí use el mismo formato.