c++ c linker bootloader

c++ - ¿Por qué el programa general generalmente comienza en 0x8000?



linker bootloader (5)

Depende del sistema, y ​​los programas comienzan en diferentes direcciones en diferentes sistemas. En Unix, es habitual (o tal vez requerido por Posix) utilizar la dirección 0 como puntero nulo y no asignar la primera página de la memoria virtual, de modo que eliminar la referencia de un puntero nulo dará como resultado una violación de segmento. Sospecho que otros sistemas que usan la 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 de solo lectura, y llenarla con ceros, hacer que un puntero nulo se comportara como si fuera una cadena vacía, un puntero a "" . Eso se remonta a hace unos 25 años, sin embargo .)

Esperaría que incluso hoy en día, algunos sistemas integrados cargan el programa comenzando en la dirección 0.

No soy nuevo en el gestor de arranque y el SW del sistema, 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.

¿El tamaño mínimo del gestor de arranque para un programa general es de hasta 0x8000 ? ¿O es el tamaño de bloque mínimo de la ROM que debe asignarse 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 un punto de vista de dirección virtual.

Aprecio todo, tu 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 la 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 inicio del programa general de la dirección. los 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 estaría ubicado en BootROM durante el arranque (arranque en frío).

Ummm, pero no estoy seguro ...


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


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.


Es algo arbitrario, y en Linux, al menos decidido por el enlazador. 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 mirando 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]


Sospecho que en muchos casos los primeros 32K estaban reservados para el uso del código de los monitores / ram. En muchas tablas de evaluaciones 8051, no era poco común establecer de forma predeterminada 0x1000 o 0x2000 para todas las aplicaciones, según el monitor residente (algunas funcionaban también como depuradoras).

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