| Volver menú revistas | Volver página anterior |
|
El Amiga Me Encanta ha conseguido el permiso por escrito de IDG Comunications España para ofrecer los artículos de la revista Amiga World España. |
| N° 8 - Marzo 1990 | |
INICIACION AL LENGUAJE |
Este tema ha sido desde hace muchísimo tiempo como un tabu, pues no había información alguna de como realmente se ejecutaba un fichero. Antes de insertarnos de lleno en el tema daré algunas nociones básicas para su posterior utilización y entendimiento, en el que resalto el tema de la multitarea, en el cual varios programas se ejecutan independientemente. Aquí juega un papel importantísimo el sistema de ficheros desarrollado para este fin. Nunca antes un ordenador personal había conseguido mayor agilidad a la hora de almacenar y ejecutar varios programas sin que se cruzasen en memoria. Esto es gracias a la relocalización del programa, es decir, la propiedad para cambiar las direcciones de las instrucciones que utilicen posiciones absolutas. Por eso a la hora de programar nunca se aconseja utilizar posiciones absolutas o fijas, sino utilizar la correspondiente etiqueta. Otro tema a tener en cuenta es el de la memoria. El Amiga chequea las diferentes partes de que consta el programa para reservar la memoria para su posterior lectura, debiendo haber mucha organización, pues cualquier mínimo error a la hora de esta asignación haría aparecer el consiguiente guru. Siempre se recomienda dejar tranquilo al Amiga a la hora de cargar ficheros y no intentar abrir directorios en el Workbench o hacer cosas extrañas. También hemos de ver algunas definiciones que utilizaremos posteriormente, como son las referencias externas, los ficheros objeto, ficheros de lectura o ejecutables, las unidades de programa y los hunks. Las referencias externas son como su nombre indica referencias producidas directamente por el ensamblador, que posteriormente van a ser utilizadas por otra parte del programa y unidas por el Linker. Le aconsejo repasar los programas de los primeros capítulos en los que se insertaban referencias XREF para que la parte principal del programa las utilizara. Simplemente es un medio de comunicación entre las distintas partes de las que puede constrar un programa. Los ficheros objeto son los producidos directamente por el ensamblador o compilador, no por el Linker, pudiendo contener como antes hemos dicho, referencias externas para unirse con más ficheros objetos. Contiene asimismo unidades de programa. Los ficheros de lectura o ejectuables son aquellos que contienen uno o más ficheros objetos que no debe contener referencias externas sin resolver. Es en resumen cualquier programa que se introduce mediante CLI o Workbench. Las unidades de programa son los elementos más pequeños que puede manejar el Linker. Estos pueden contener uno o más hunks (ahora los veremos) y de referencias externas sin resolver. Quizá el elemento más importante sea el hunk, que traducido diríamos trozo o porción. Consiste en un bloque de código o datos, información para relocalizar o una lista de referencias externas. Puede contener datos inicializados o no inicializados (BBS, no aptos para relocalización). También puede contener símbolos, es decir, el nombrar internamente las mismas etiquetas y subrutinas que utilizamos a la hora de realizar cualquier programa. Esto es valiosísimo para un posterior estudio detallado con el Debugger, un programa destinado a la visualización de la ejecución paso a paso del fichero ejectutable. El Debugger más recomendado es el Metascope Debugger de Metadigm versión 1.11, pero también hay otros incluso de dominio público. Detallándonos en este mismo, permite visualizar la ejecución de un programa mnemónico por mnemónico o por niveles (saltándose las subrutinas). También es posible ver todos los registros cada vez que se hace el seguimiento, así como poner puntos de parada para que al ejecutar el programa se pare en los puntos prefijados.
Volviendo a los Hunks, hayq ue decir que existen diferentes y variados tipos, unos dentro de los ficheros objeto y otros ya dentro de los ficheros ejecutables o de lectura. Cada uno de estos hunks lleva una larga palabra como identificación. En el cuadro 1 está la relación de hunks con sus códigos. Para que toda esta teoría pueda resultar monótona hemos ilustrado la estructura de los ficheros objetos y ejecutables con un ejemplo a seguir por cualquier persona. Antes de repasar todos los tipos de hunks hemos de decir que todo su manejo de números se hace en largas palabras.
|
|
Cada
una de estas |
|---|
Hunk relocalización 16 bits
Tiene la misma estructura que el anterior tipo de hunk, con la simple
diferencia que el contador es en 16 bits y no en 32.
Hunk relocalización 8 bits
Con la misma estructura que los dos anteriores tipos.
Hunk referencia externa
Este bloque contiene referencias externas que posteriormente resuelve
el Linker. Para recordarlo de nuevo estas referencias eran producidas
por las directivas del ensamblador XREF y XDEF destinadas a producir
una unión de rutinas y datos con los programas que realizábamos.
La estructura de este hunk es la siguiente: Una larga palabra con el
primer byte indicativo del tipo de directiva utilizado. Los restantes
tres bytes contienen la longitud del nombre, el nombre de la referencia
o definición, offset de la definición. 0 en larga palabra
indicativo del fin del hunk. El byte indicativo del tipo de directiva
siendo: 1 para la definición externa XDEF 129 para la definición
externa.
Xref Hunk simbolo
Se utiliza para insertar una tabla de símbolos que posteriormente
utilizará el debugger para su investigación más
profunda del programa. Estos símbolos corresponden al etiquetado
que se ha llevado a cabo en la realización del mismo programa,
así tendrá constancia de esto mismo cuando ejecute poco
a poco el mismo.
Hunk información Debugger
También se utiliza para su posterior visualiación con
el debugger, permitiéndose insertar información adicional
(REM en Basic) en las complicadas estructuras del Amiga. Esto no hace
que el Amigados lo cargue en memoria a la hora de ejecturar el programa,
simplemente es el debugger el que lo inserta.
Hunk final
Indica el final de un hunk, consistiendo simplemente es una doble palabra
conteniendo el valor $3F2.
CUADRO 3 HUNK 0 ------ $40000: 2C780004 23CE0000 004A43F9 00000052 $40010: 4EAEFE68 23C00000 004E2C79 0000004E $40020: 4EAEFFCA 23C00000 00424EAE FFC423C0 $40030: 00000046 2c790000 004A4EB9 00000000 $40040: 4E750000 00000000 00000000 00000000 $40050: 0000646F 732E6C69 62726172 79000000 HUNK 1 ------ $41000: 243C0000 0026263C 00000014 22390000 $41010: 00422C79 0000004E 4EAEFFD0 13FC0002 $41020: 0000003A 4E750A45 73746F20 65732065 $41030: 6C206D65 6E73616A 650A0000 |
CUADRO 4 HUNK 0 ------ $40000: 2C780004 23CE0004 004A43F9 00040052 $40010: 4EAEFE68 23C00004 004E2C79 0004004E $40020: 4EAEFFCA 23C00004 00424EAE FFC423C0 $40030: 00040046 2C790004 004A4EB9 00041000 $40040: 4E750000 00000000 00000000 00000000 $40050: 0000646F 732E6C69 62726172 79000000 HUNK 1 ------ $41000: 243C0004 1026263C 00000014 22390004 $41010: 00422C79 0004004E 4EAEFFD0 13FC0002 $41020: 0004103a 4E750A45 73746F20 65732065 $41030: 6C206D65 6E73616A 650A0000 |
LISTADO 1
IDNT TEST
XDEF STARTUP
XDEF _stdin
XDEF _stdout
XDEF _SysBase
XDEF _DOSBase
XREF START
STARTUP MOVE.L 4,A6 obtiene dirección SysBase
MOVE.L A6,_SysBase la salva
LEA DOSName,A1 apunta al nombre DOS'
JSR -$198(A6) abre libreria
MOVE.L D0,_DOSBase salva la dirección base
move.L DOSBase,A6 direción de base DOS'
JSR -$36(A6) Entrada manejo de fichero
MOVE.L D0,_stdin salvarlo
JSR -$3C(A6) Salida manejo de fichero
MOVE.L D0,_stdout salvarlo
MOVE.L _SysBase,A6 obtener dirección SysBase
JSR START ir inicio prog.principal
RTS
_stdin DS.L 1
_stdout DS.L 1
_SysBase DS.L 1
_DOSBase DS.L 1
DOSName DC.B 0dos.library',0
END
0000: 000003E7 00000001 54455354 000003E9 ........TEST....
0010: 00000018 2C780004 23CE0000 004A43F9 ....,x..#....JC.
0020: 00000052 4EAEFE68 23C00000 004E2C79 ...RN..h#....N,y
0030: 0000004E 4EAEFFCA 23C00000 00424EAE ...NN...#....BN.
0040: FFC423C0 00000046 2C790000 004A4EB9 ..#....F,y...JN.
0050: 00000000 4E750000 00000000 00000000 ....Nu..........
0060: 00000000 0000646F 732E6C69 62726172 ......dos.librar
0070: 79000000 000003EC 00000007 00000000 y...............
0080: 00000036 00000030 00000026 0000001C ...6...0...&....
0090: 00000016 0000000C 00000006 00000000 ................
00A0: 000003EF 01000002 5F444F53 42617365 ........_DOSBase
00B0: 0000004E 01000002 5F537973 42617365 ...N...._SysBase
00C0: 0000004A 01000002 5F737464 6F757400 ...J...._stdout.
00D0: 00000046 01000002 5F737464 696E0000 ...F...._stdin..
00E0: 00000042 01000002 53544152 54555000 ...B....STARTUP.
00F0: 00000000 81000002 53544152 54000000 ........START...
0100: 00000001 0000003C 00000000 000003F2 .......<........
OFFSET CONTENIDO COMENTARIO
------------------------------------
$0000 $000003E7 hunk unidad
$0004 $00000001 tamaño nombre unidad
$0008 $54455354 nombre de la unidad en ASCII = TEST
$000C $000003E9 hunk código
$0010 $00000018 tamaño hunk
$0014-$0073 ......... código de la unidad
$0074 $000003EC hunk relocalización 32 bits
$0078 $00000007 número de hunks a relocalizar
$007C $00000000 hunk a relocalizar comenzando de 0
$0080-$0098 ......... offset a partir base código anterior
$009C $00000000 0 para marcar fin de relocalización
$00A0 $000003EF hunk de referencias externas
$00A4 $01000002 tipo de referencia 1 (XDEF) y longitud del nombre
$00A8-$00AF ......... nombre de la definición = _DOSBase
$00B0 $0000004E offset de la definición
$00B4 $01000002 mismo caso anterior
$00B8-$00BF ......... nombre de la defición = _SysBase
..... ......... continuación del resto de las definiciones
$00F4 $81000002 tipo de referencia $81 = 121(XREF)
$00F8-$00FF ......... nombre de la referencia = START
$0100 $00000001 número de referencias
$0104 $0000003C offset de referencia
$0108 $00000000 fin bloque de referencias externas
$010C $000003F2 hunk fin
|
LISTADO 2
TTL 'Imprime'
XREF _DOSBase
XREF _stdin
XDEF START
START MOVE.L #MSG,D2 apunta comienzo mensaje
MOVE.L #20,D3 salva longitud mensaje
MOVE.L _stdin,D1 donde va el mensaje (CLI)
MOVE.L _DOSBase,A6 apunta a Libreria Base DOS
JSR -$30(A6) escribe
MOVE.B #02,POS1 prueba relocalización
RTS retorna a CLI
MSG DC.B $A,'Esto es el mensaje',$A
POS1 DS.L 00
END
|
El formato de un fichero de lectura o ejecutable producido por el Linker es parecido al fichero objeto, con la única diferencia de que el fichero ejecutable no contiene definiciones ni referencias externas. En el caso común de un fichero, comienza por el bloque de cabecera que le informa de cuantos hunks consta el fichero con sus longitudes. A continuación le siguen los hunks referidos y que corresponden a los del fichero objeto en parte. Se puede dar otro caso, el de los fichero de overlay, es decir, aquella parte del programa que puede ser leído posteriormente por el programa principal, y que contiene simplemente información y rutinas de segundo orden, es decir optativas. Esto ocurre con programas muy largos, para que sean parcialmente utilizados por los ordenadores de configuración basica. Como es bastante difícil agotar la memoria del Amiga con nuestros cortos programas, veremos el único tipo de hunk indicativo de los ficheros ejecutables, el de la cabecera.
Hunk cabecera
Este hunk es digamos el hunk más importante de todos los vistos.
Contiene información sobre el fichero que tiene que leer, como
es el número de hunks y sus longitudes. La estructura es la siguiente:
valor del tipo de hunk: $000003F3, librerías residentes, opción
muy poco utilizada, a 0, número de hunks (P), primer hunk, generalmente
hunk 0 (U), último hunk que viene dado por la fórmula
U-P+1, longitud de los hunks, primer hunk, hunk final. Ahora veamos
todo lo dicho anteriormente mediante dos ejemplos, uno con ficheros
objetos para observar las referencias externas y otro ejecutable para
ver la estructura de la cabecera y relocalizaicón. Para el primer
ejemplo utilizaremos el programa del listado 1. (sálvelo en su
disco ensamblador como test): Ahora que ya hemos visto que todo concuerda
con lo dicho anteriormente voy a explicar algunos detalles. Todos los
valores utilizados son en largas palabras y para obtener su valor en
bytes hay que multiplicar por cuatro.
Antes de realizar el ensamblado copia el fichero del listado 2 a RAM: por ejemplo, con el nombre JUNTA mediante el comando copy OBJETO RAM:JUNTA. Este nos servirá, si recuerdas el capítulo 1, para unir las referencias externas que ahora necesita este último programa, como por ejemplo la base de la librería DOS. Ahora salva el programa principal anterior como test y ejecuta los siguientes comandos:
c/assem test -o OBJETO
c/link RAM:JUNTA,OBJETO to PRG
|
Un
fichero objeto es el |
|---|
el programa final se llama PRG, puedes ejecutarlo, en una simple visualiación en pantalla de una frase. Ahora pasemos a realizar el proceso anterior para visualizar los códigos hexadecimales y ASCII mediante el comando: type >RAM:hex PRG opt h. El resultado está en el cuadro 2. Ahora pasemos a explicar detenidamente cómo realiza la lectura en memoria de nuestro fichero ejecutable. Primero carga la cabecera para enterarse de cuantos hunks y de sus longitudes para hacer la reserva de la memoria de 96 y 60 bytes respectivamente por los hunks 0 y 1, a continuación realiza la lectura en esos espacios de memoria reservados de los hunks. Por último queda la fase más importante, relocalización. Supongamos que los dos hunks se han insertado en las posiciones de memoria $40000 y $41000. La visualización sería como la del cuadro 3. Para realizar la relocalización en el primer hunk el Amigados suma el valor $40000 a los 7 offsets que componen la lista dentro del hunk. Utilicemos por ejemplo los valores de los offsets 6 y 7 ($6 y $C), sumando $6 al $40000 (ya que es donde se cargó el hunk) nos da la posición de memoria $40006. Ahora sumamos $40000 a la palabra larga que corresponde en es aposición de memoria ($0000004A + $40000 = $4004A). También lo hacemos al offset con el valor $C, en donde habrá que sumar $40000 a lo que haya en la posición $4000C ($00000052 + $40000 = $400052), así consecutivamente con todos los offsets del hunk 0. Pero todavía falta un valor que insertar en el hunk 0 por parte del hunk 1 con el valor $41000 (ver línea en $00B4 de la estructura del fichero). Este único offset contiene el valor $3C. Aplicando la fórmula será en la posición de memoria $4003C la que habrá que sumarle el valor $41000. Ahora pasamos a la relocalización del hunk 1, habiendo 2 por parte del mismo hunk y otros dos por parte del otro hunk, el offset 1 con valor $20, la conclusión será sumar $41000 a la posición $40000 + $20 (en esa posición se encuentra el valor $0000003A pasando a ser $4103A). Lo mismo ocurre en el offset 2. Por último queda los dos offsets por parte del hunk 0. Estos dos contienen los valores $E y $14, por lo tanto habrá que sumar $40000 a lo que haya en las posiciones de memoria $4100E y $41014. El resultado final de toda esta operación se muestra en el cuadro 4. Este mismo proceso lo puedes llevar a cabo para cualquier fichero ejecutables del Amiga. Aunque parece un poco complicado una vez que haya resuelto el enigma una vez el resto te parece igual. También con estos diez capítulos puede realizar un programa que visualice los hunks para poder editarlos.
Y nada más, este es el final del cursillo de lenguaje ensamblador, dedicado exclusivamente al interior de nuestro Amiga. Hasta el próximo cursillo, probablemente sobre el C.
| Volver menú revistas | Volver página anterior |