2012-03-13 17 views
43

No soy nuevo en el gestor de arranque y el sistema SW, pero no sé el origen de la razón por la cual el programa general comienza en 0x8000. Ya sé que la dirección 0x8000 se ha utilizado como dirección de inicio en el programa C/C++ normal.¿Por qué el programa general generalmente comienza en 0x8000?

¿El tamaño mínimo del gestor de arranque para un programa general toma hasta 0x8000? ¿O es el tamaño de bloque mínimo de la ROM que se debe asignar al cargador de arranque de 32 KB? ¿O hay otra razón?

Me gustaría saber sobre esto, histórica o lógicamente, y desde el punto de vista de una dirección virtual.


Agradezco a todos, su tiempo y ayuda con esto. Para hacer la pregunta más clara, la pregunta está relacionada con la dirección virtual, no con la física.

Básicamente estoy de acuerdo con la opinión de R desde el punto de vista de la dirección de memoria física.

Sin decir un sistema específico que sea diverso, por ejemplo Linux (incluso en Android), RTOS general (núcleo y los demás, especialmente la sección del enlazador ARM), todos usan la dirección 0x8000 como programa general de la dirección de inicio. llamados crt_begin.o, crt.o, etc. ubicados en 0x0 con cargador existen en esta área.

Por lo tanto, supongo que el tamaño mínimo del gestor de arranque para el programa general es de 32 KB, teniendo en cuenta el tamaño del bloque si se encuentra en BootROM durante el arranque (arranque en frío).

Ummm, pero no estoy seguro ...

+16

¿De qué sistema está hablando aquí? –

+2

No tengo ninguna fuente confiable para esto, pero puedo hacer una suposición calificada. Históricamente, muchos procesadores, en particular los de 8 bits, tienen la función denominada [página cero] (http://en.wikipedia.org/wiki/Zero_page), lo que significa que las celdas de memoria en las direcciones 0x00 - 0xFF tienen soporte de instrucciones para ejecuta más rápido. Creo que esto fue introducido por Motorola en aquellos días, ya que tenían registros de E/S mapeados en memoria en los antiguos MCU como 6800. -> – Lundin

+2

Por lo tanto, querría que esta primera área de memoria estuviera ocupada por celdas RAM o registros especiales . Entonces tiene sentido que la parte del espacio de direcciones que viene después de la página cero sea de la misma naturaleza: RAM y/o registros. Esto tomaría mucho kb, tal vez hasta 0x6000 o algo así. Supongo que era conveniente colocar la ROM (memoria de programa) en una dirección pareja y 0x8000 era conveniente. Estoy bastante seguro de que la respuesta a esta pregunta se puede encontrar en los primeros diseños de procesadores Motorola. – Lundin

Respuesta

19

En general, en todos menos en los sistemas integrados más pequeños, la plataforma ABI diseñador quiere evitar tener que las direcciones más bajas en uso de manera que desreferencias puntero NULL puede atrapado. Tener varios KB de direcciones nunca válidas le da algo de seguridad adicional si el puntero nulo se desreferencia con una matriz o un miembro de estructura desplazada, como en null_ptr->some_member.

+3

No creo que este sea el motivo, he trabajado con varios sistemas integrados donde la dirección 0 es válida y la memoria direccionable, mientras que al mismo tiempo la NVM comienza en 8000. – Lundin

+5

... particularmente porque la dirección 0x8000 existía antes de la C el lenguaje y los indicadores NULL se hicieron populares. ¿Quizás incluso antes de que se inventara C? – Lundin

+0

Según tengo entendido, no quiere que los punteros "reales" sean 0, nunca, incluso en sistemas en los que HW está de acuerdo. Entonces, si 'malloc()' devuelve 0, sabrá que falló. Por lo tanto, en sistemas donde la dirección 0 no atrapa, la memoria generalmente se asigna para fines específicos, como controladores de interrupción. – MSalters

6

Depende del sistema, y ​​los programas comienzan en diferentes direcciones en sistemas diferentes. En Unix, es habitual (o incluso requerido por Posix) utilizar la dirección 0 como puntero nulo y no asignar la primera página de la memoria virtual , por lo que eliminar referencias a un puntero nulo dará como resultado una infracción de segmento. Sospecho que otros sistemas que usan dirección 0 como un puntero nulo se comportan de manera similar (pero la cantidad que reservan puede variar). (Históricamente, era habitual asignar la primera página como solo, y llenarla con ceros, hacer que un puntero nulo se comportaría como si fuera una cadena vacía, un puntero a "". Eso es alrededor de 25 años , sin embargo.)

yo esperaría que incluso hoy en día, algunos sistemas embebidos no cargar el programa partir de la dirección 0.

2

me sospecho que en muchos casos el primer 32K fue reservado para los monitores uso de código/ram. En muchas tablas de evaluaciones 8051, no era raro que se usara de manera predeterminada 0x1000 o 0x2000 para todas las aplicaciones, dependiendo del monitor residente (algunas funcionaban también como depuradoras).

32K podría ser su espacio de cargadores u-boot/etc.

3

Es un tanto arbitrario, y en Linux, al menos decidido por el vinculador. La idea general es reservar espacio para detectar excepciones de punteros NULL. Para ayudar a evitar que las referencias al puntero NULL del espacio del kernel ejecuten código de usuario arbitrario en modo kernel, Linux evita que se mapee la parte inferior de la memoria. /proc/sys/vm/mmap_min_addr controla la dirección más baja que puede asignar (puede cambiarla a 0 y asignar una página a 0 si lo desea).

En Linux puede ver la asignación de memoria buscando en /proc. Por ejemplo,

genwitt ~> cat /proc/self/maps 
00400000-0040c000 r-xp 00000000 08:01 354804        /bin/cat 
0060b000-0060c000 r--p 0000b000 08:01 354804        /bin/cat 
0060c000-0060d000 rw-p 0000c000 08:01 354804        /bin/cat 
01dda000-01dfb000 rw-p 00000000 00:00 0         [heap] 
7f5b25913000-7f5b25a97000 r-xp 00000000 08:01 435953      /lib64/libc-2.14.1.so 
7f5b25a97000-7f5b25c97000 ---p 00184000 08:01 435953      /lib64/libc-2.14.1.so 
7f5b25c97000-7f5b25c9b000 r--p 00184000 08:01 435953      /lib64/libc-2.14.1.so 
7f5b25c9b000-7f5b25c9c000 rw-p 00188000 08:01 435953      /lib64/libc-2.14.1.so 
7f5b25c9c000-7f5b25ca1000 rw-p 00000000 00:00 0 
7f5b25ca1000-7f5b25cc2000 r-xp 00000000 08:01 436061      /lib64/ld-2.14.1.so 
7f5b25cd2000-7f5b25e97000 r--p 00000000 08:01 126248      /usr/lib64/locale/locale-archive 
7f5b25e97000-7f5b25e9a000 rw-p 00000000 00:00 0 
7f5b25ec0000-7f5b25ec1000 rw-p 00000000 00:00 0 
7f5b25ec1000-7f5b25ec2000 r--p 00020000 08:01 436061      /lib64/ld-2.14.1.so 
7f5b25ec2000-7f5b25ec3000 rw-p 00021000 08:01 436061      /lib64/ld-2.14.1.so 
7f5b25ec3000-7f5b25ec4000 rw-p 00000000 00:00 0 
7fff18c37000-7fff18c58000 rw-p 00000000 00:00 0       [stack] 
7fff18d0c000-7fff18d0d000 r-xp 00000000 00:00 0       [vdso] 
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0     [vsyscall]
2

Creo que la respuesta está más relacionada con el manejo de interrupciones. Las direcciones del manejador de interrupciones se configuran en hardware. En Intel 8086, había una tabla de traducción directa en el código del controlador de interrupciones y la rutina de manejo de interrupciones correspondiente. Probablemente, esto fue hecho por algún circuito combinatorio y, por lo tanto, para preservar la compatibilidad directa, hubiera sido más sensato colocarlos al comienzo de la memoria en lugar de al final para evitar los cambios cada vez. Entonces, la dirección de inicio de la ejecución estaría en el otro extremo de la memoria. Además, era necesario que hubiera suficiente código en ese bloque para cargar un programa de segmento de memoria y una instrucción de salto para pasar a ejecutar el código desde esa dirección de código.

Cuestiones relacionadas