2009-02-05 10 views

Respuesta

16

[EDIT] Actualizado

Cada vez que vea un operando de memoria que se ve algo como ds:0x00923030, que es un modo de direccionamiento segmento relativa. La dirección real referida tp está en la dirección lineal 0x00923030 con respecto a la dirección base del registro de segmento ds.

La segmentación de memoria en la arquitectura x86 es algo confusa, y creo que Wikipedia hace un buen trabajo al explicarla.

Básicamente, x86 tiene una serie de especiales segmento registros: cs (código segmento), ds (datos segmento), es, fs, gs, y ss (pila segmento). Cada acceso a la memoria está asociado con un cierto registro de segmento. Normalmente, no se especifica el registro de segmento, y dependiendo de cómo se accede a la memoria, se utiliza un registro de segmento predeterminado. Por ejemplo, el registro cs se usa para leer las instrucciones.

Cada registro de segmento tiene una dirección base cierta y un límite. La dirección base determina la dirección física a la que corresponde la dirección lineal 0x00000000, y el límite determina la dirección lineal máxima permitida para ese segmento. Por ejemplo, si la dirección base era 0x00040000 y el límite era 0x0000FFFF, entonces las únicas direcciones lineales válidas serían 0x00000000 a 0x0000FFFF, y las direcciones físicas correspondientes serían 0x00040000 a 0x0004FFFF.

Por lo tanto, la dirección física en la que reside la subrutina que se llama está dada por la dirección base almacenada en el registro de segmento ds, más 0x00923030. Pero aún no hemos terminado - la instrucción tiene la palabra ptr en ella. Esto agrega un nivel adicional de direccionamiento indirecto, por lo que el objetivo real de la subrutina es la dirección almacenada en la ubicación ds:0x00923030.

en al & sintaxis T (aceptado por el ensamblador GNU), la instrucción se escribiría de la siguiente manera:

lcall *ds:0x00923030 

Para los detalles morbosos completo de lo que la instrucción es así, consulte la 80386 reference manual. Esta variante particular de la instrucción es "CALL r/m16" (llamada cerca del registro indirecto/indirecto de memoria).

+0

No bastante, creo, hay una indirección involucrada. Por lo tanto, debe ser: La dirección física a la que reside la subrutina que se llama está dada por el valor en la dirección base almacenada en el registro del segmento ds más 0x00923030. –

+0

Un selector de segmento no apunta a una dirección física como dices, sino a una dirección lineal. La dirección física en su lugar se obtiene en el paso final, cuando la dirección lógica ya se ha resuelto a una dirección lineal. – newgre

+0

Gracias. Es genial que las personas estén dispuestas a compartir su experiencia en un área en particular con los demás. Me has ahorrado una gran cantidad de tiempo. –

2

IIRC, toma el valor del registro DS (y lo desplaza a la izquierda 4 bits), suma al valor inmediato dado, recupera un valor dword de la ubicación de la memoria resultante, que se convierte en la dirección a llamar. (EDITAR: esto es válido para el modo real de 16 bits, para el modo protegido ver las otras respuestas.)

+0

esto está mal, el desplazamiento no se agrega al valor del registro ds. Esta es en realidad una dirección lógica. – newgre

+0

Tienes razón, estaba pensando en el modo real. –

9

Este código de operación específico realiza una llamada a través de la dirección virtual (32 bits aquí) que reside en la ubicación apuntada por la dirección lógica ds:[00923030h].
una dirección lógica se compone de dos componentes:

  1. Un selector de segmento de 16 bits, ds en este caso, que es básicamente un índice en la tabla de descriptores (global/local), gestionado por el sistema operativo. un selector de este tipo también mantiene información sobre los derechos de acceso para el segmento dado que se comprueba en el acceso (nivel de privilegio actual, CPL)
  2. A de 32 bits compensado
    se calcula entonces la dirección final de la siguiente manera: dirección base obtienen de selector + offset

Tenga en cuenta que el cálculo anterior indica una dirección lineal, no una física (ver manuales Intel volume 3a, figura 2.2), que se traduce a continuación, a través del mecanismo estándar para 4 KB de paginación, es decir, la dirección consiste en un índice al directorio de la página, a la tabla de páginas y a un desplazamiento en la página seleccionada. Sin embargo, tenga en cuenta que todos los sistemas operativos de la corriente principal utilizan el llamado modelo de memoria plana, lo que significa que todos los selectores de segmentos apuntan a la dirección 0x00000000 con el límite establecido en 0xFFFFFFFF, que es la razón por la que puede realizar el reparto entre todos los segmentos. para (fácil) explotación de desbordamientos de búfer.

La instrucción de ensamblador que ha dado, es muy probable que sea una llamada a través de la tabla de importación de dirección (vea el artículo grande this para más detalles) de un archivo ejecutable, es decir, es poco probable que sea una llamada de subrutina ordinal.
Este tipo de código es emitido por los compiladores porque la dirección virtual final de una función importada desde un dll externo no se puede conocer en general en el momento de la compilación (debido a la rebase de dlls). Al utilizar una construcción de llamada de este tipo, el cargador del sistema operativo puede insertar la dirección virtual correcta en el puntero de dirección por la dirección lógica y al compilador no le debe importar qué dirección de todas formas tenga la función final.

+0

Gracias. Este es de hecho el código generado por un compilador para una llamada de función virtual. Su respuesta ha ayudado mucho y me ha ahorrado mucho tiempo. –

Cuestiones relacionadas