¿Cuál es el segmento y el desplazamiento en el direccionamiento de memoria en modo real?

Estoy leyendo sobre direccionamiento de memoria. Leí sobre el offset del segmento y luego sobre el offset del descriptor. Sé cómo calcular las direcciones exactas en modo real. Todo esto está bien, pero no puedo entender qué es exactamente el desplazamiento. Dondequiera que leo:

En modo real, los registros son solo de 16 bits, por lo que solo puede abordar hasta 64k. Para permitir el direccionamiento de más memoria, la dirección קד se calcula a partir del segmento * 16 + desplazamiento.

Aquí puedo entender la primera línea. Tenemos 16 bits, por lo que podemos abordar hasta 2 ^ 16 = 64k.

Pero, ¿qué es esta segunda línea? ¿Qué representa el segmento? ¿Por qué lo multiplicamos con 16? por qué agregamos compensación Simplemente no puedo entender lo que es este desplazamiento? ¿Alguien puede explicarme o darme un enlace para esto por favor?

En la memoria de modo real x86, la dirección física es de 20 bits y está calcolated:

PhysicalAddress = Segment * 16 + Offset 

Verifique también: Gestión de memoria en modo real

Cuando Intel estaba construyendo el 8086, existía un caso válido para tener más de 64 KB en una máquina, pero no había manera de que alguna vez utilizara un espacio de direcciones de 32 bits. En aquel entonces, incluso un megabyte era una gran cantidad de memoria. (¿Recuerda la cita infame “640K debería ser suficiente para cualquiera”? Es esencialmente una mala traducción del hecho de que en aquel entonces, 1MB estaba volviendo enorme ). La palabra “gigabyte” no sería de uso común durante otros 15-20 años. , y no se estaría refiriendo a RAM por otros 5-10 años después de eso.

Entonces, en lugar de implementar un espacio de direcciones tan grande que “nunca” se utilizaría por completo, lo que hicieron fue implementar direcciones de 20 bits. Todavía usaban palabras de 16 bits para las direcciones, porque después de todo, este es un procesador de 16 bits. La palabra superior era el “segmento” y la palabra más baja era el “desplazamiento”. Sin embargo, las dos partes se solaparon considerablemente: un “segmento” es un fragmento de memoria de 64 KB que comienza en (segment) * 16 , y el “desplazamiento” puede apuntar a cualquier parte dentro de ese fragmento. Para calcular la dirección real, multiplique la parte del segmento de la dirección por 16 (o desplace la izquierda en 4 bits … lo mismo), y luego agregue la compensación. Cuando termines, tienes una dirección de 20 bits.

  19 4 0 +--+--+--+--+ | segment | +--+--+--+--+--+ | offset | +--+--+--+--+ 

Por ejemplo, si el segmento era 0x8000 y el desplazamiento era 0x0100, la dirección real sale ((0x8000 < < 4) + 0x0100) == 0x80100 .

  8 0 0 0 0 1 0 0 --------------- 8 0 1 0 0 

Sin embargo, las matemáticas rara vez son tan limpias: 0x80100 se puede representar literalmente con miles de combinaciones de segmentos diferentes: 4096, si mis cálculos son correctos.

Quiero agregar una respuesta aquí solo porque he estado buscando en internet tratando de entender esto también. Las otras respuestas estaban omitiendo una información clave que obtuve del enlace presentado en una de las respuestas. Sin embargo, casi me lo perdí. Al leer la página vinculada, todavía no entendía cómo funcionaba esto.

Probablemente, el problema que probablemente tenía era el de entender realmente cómo el Commodore 64 (procesador 6502) presentaba la memoria. Utiliza una notación similar a la memoria de direcciones. Tiene 64k de memoria total y usa valores de 8 bits de PAGE: OFFSET para acceder a la memoria. Cada página tiene 256 bytes de longitud (número de 8 bits) y el desplazamiento apunta a uno de los valores en esa página. Las páginas están espaciadas una detrás de la otra en la memoria. Así que la página 2 comienza donde termina la página 1. Iba al 386 pensando el mismo estilo. Esto no es asi

El modo real está usando un estilo similar, incluso si tiene un texto diferente SEGMENTO: DESPLAZAMIENTO. Un segmento tiene 64k de tamaño. Sin embargo, los segmentos en sí mismos no están dispuestos de manera consecutiva como el Commodore. Están espaciados a 16 bytes de distancia el uno del otro. Offset todavía funciona de la misma manera, indicando cuántos bytes del segmento de la página \ comienzan.

Espero que esta explicación ayude a cualquier otra persona que encuentre esta pregunta, me ha ayudado a escribirla.

Puedo ver que la pregunta y las respuestas tienen algunos años, pero hay una statement incorrecta de que solo existen registros de 16 bits dentro del modo real.

Dentro del modo real, los registros no son solo de 16 bits, porque también hay registros de 8 bits. Cada uno de estos registros de 8 bits es parte de un registro de 16 bits que se divide en una parte inferior y una parte superior de un registro de 16 bits.

Y comenzando el modo real con un 80386+ nos convertimos en registros de 32 bits y adicionalmente dos nuevos prefijos de instrucción, uno para anular / revertir el tamaño de operando por defecto y otro para anular / revertir el tamaño de dirección predeterminado de una instrucción dentro de un segmento de código.

Estos prefijos de instrucción se pueden usar en combinación para invertir el tamaño del operando y el tamaño de la dirección juntos para una instrucción. Dentro del modo real, el tamaño predeterminado del operando y el tamaño de la dirección son 16 bits. Con estos dos prefijos de instrucción podemos usar un ejemplo de operando / registro de 32 bits para calcular un valor de 32 bits en un registro de 32 bits, o para mover un valor de 32 bits hacia y desde una ubicación de memoria. Y podemos usar todos los registros de 32 bits (tal vez en combinación con una base + índice * escala + desplazamiento) como un registro de dirección, pero la sum de la dirección efectiva no tiene que exceder el límite del segmento de 64 kb. .

(En la página OSDEV-Wiki podemos encontrar en la tabla el “prefijo de sustitución de tamaño de dirección y operando” que el “prefijo de operando 0x66” y el “prefijo de dirección 0x67” es N / A (no aplicable) para el modo real y el modo virtual 8086. http://wiki.osdev.org/X86-64_Instruction_Encoding
Pero esto es totalmente incorrecto, porque en el manual de Intel podemos encontrar esta afirmación: “Estos prefijos se pueden usar en modo de dirección real, así como en modo protegido y en modo virtual-8086”).

Comenzando con un Pentium MMX, nos convertimos en ocho MMX-Registers de 64 bits.
Comenzando con un Pentium 3 nos convertimos en ocho registros XMM de 128 bits.
..

Si no estoy equivocado, entonces el registro YMM de 256 bits y el registro ZMM de 512 bits y el registro general de 64 bits de 64 bits no se pueden usar en el modo real.

Puñal

Ejemplo mínimo

Con:

  • desplazamiento = msg
  • segmento = ds
 mov $0, %ax mov %ax, %ds mov %ds:msg, %al /* %al contains 1 */ mov $1, %ax mov %ax, %ds mov %ds:msg, %al /* %al contains 2: 1 * 16 bytes forward. */ msg: .byte 1 .fill 15 .byte 2 

Entonces, si quieres acceder a la memoria por encima de 64k:

 mov $0xF000, %ax mov %ax, %ds 

Tenga en cuenta que esto permite direcciones de más de 20 bits de ancho si utiliza algo como:

 0x10 * 0xFFFF + 0xFFFF == 0x10FFEF 

En los procesadores anteriores que solo tenían 20 cables de dirección, simplemente se truncó, pero más tarde se complicaron las cosas con la línea A20 (21º cable de dirección): https://en.wikipedia.org/wiki/A20_line

En un repository GitHub con la plantilla requerida para ejecutarlo.

Un registro de 16 bits solo puede abordar hasta 0xFFFF (65.536 bytes, 64 KB). Cuando eso no fue suficiente, Intel agregó registros de segmentos.

Cualquier diseño lógico simplemente habría combinado dos registros de 16 bits para hacer un espacio de direcciones de 32 bits (por ejemplo, 0xFFFF : 0xFFFF = 0xFFFFFFFF ), pero nooooo … Intel tenía que ponerse muy raro con nosotros.

Históricamente, el bus frontside (FSB) solo tenía 20 líneas de dirección y, por lo tanto, solo podía transmitir direcciones de 20 bits. Para “rectificar” esto, Intel ideó un esquema en el que los registros de segmentos solo amplían su dirección en 4 bits (16 bits + 4 = 20, en teoría).

Para lograr esto, el registro del segmento se desplaza hacia la izquierda desde su valor original en 4 bits, luego se agrega a la dirección en su registro general (por ejemplo [es:ax] = ( es < < 4 ) + ax ) . Nota: el desplazamiento a la izquierda de 4 bits equivale a multiplicar por 16 .

Eso es. Aquí hay algunos ejemplos ilustrativos:

 ;; everything's hexadecimal [ 0:1 ] = 1 [ F:1 ] = F1 [ F:0 ] = F0 [ F:FF] = 1EF ; [F becomes F0, + FF = 1EF] [ F000 : FFFF ] = FFFFF (max 20-bit number) [ FFFF : FFFF ] = 10FFEF (oh shit, 21-bit number!) 

Por lo tanto, aún puede abordar más de 20 bits. ¿Lo que pasa? La dirección "se ajusta", como la aritmética del módulo (como consecuencia natural del hardware). Entonces, 0x10FFEF convierte en 0xFFEF .

¡Y ahí lo tienes! Intel contrató a algunos ingenieros tontos, y tenemos que vivir con eso.