manual para la implementación de programas que integren los lenguajes java y ensamblador

25
Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador. Una guía práctica con ejemplos Versión 1.0 Elaboró: Peniel Ruiz López Unistmo 10/17/2011

Upload: peniel-ruiz

Post on 28-Jul-2015

1.363 views

Category:

Documents


9 download

DESCRIPTION

Java, Ensamblador, Librerias Dinámicas.

TRANSCRIPT

Page 1: Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador

Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador.

Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador. Una guía práctica con ejemplos

Versión 1.0

Elaboró: Peniel Ruiz López Unistmo

10/17/2011

Page 2: Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador

Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador.

Manual para la Implementación de Programas

que Integren los Lenguajes Java y Ensamblador. Una guía práctica con ejemplos.

Peniel Ruiz López.

Page 3: Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador

Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador.

Page 2

Contenido 1. GENERALIDADES ............................................................................................ 3

1.1 INTRODUCCIÓN. ........................................................................................... 3

1.2 OBJETIVOS. ..................................................................................................... 3

1.3 A QUIEN VA DIRIGIDO EL MANUAL. ............................................................. 3

1.4 ACRÓNIMOS, ANGLICISMOS Y ABREVIATURAS EMPLEADAS. ..................... 3

2. EL LENGUAJE JAVA ........................................................................................ 4

2.1 ¿QUÉ ES JAVA? ................................................................................................ 4

3. EL LENGUAJE ENSAMBLADOR .............................................................. 4

3.1 ENSAMBLADOR .............................................................................................. 4

3.2 ENLAZADOR ................................................................................................... 4

3.3 GENERALIDADES DEL LENGUAJE .................................................................. 4

4. UTILIDAD DE LA PROGRAMACIÓN HÍBRIDA .............................. 5

4.1 CASO GENERAL ............................................................................................. 5

4.2 CASO PARTICULAR ........................................................................................ 5

6. ENTORNOS DE DESARROLLO ............................................................... 5

6.1 ECLIPSE ............................................................................................................ 5

6.2 NETBEANS ...................................................................................................... 6

6.3 MASM32 ........................................................................................................ 6

7. JAVA NATIVE INTERFACE ......................................................................... 6

7.1 INTRODUCCIÓN ............................................................................................ 6

7.2 ¿CUÁNDO USAR JNI? .................................................................................... 7

7.3 USANDO JNI PARA INVOCAR MÉTODOS NATIVOS ................................... 7

8. EJEMPLO DE JASM ........................................................................................ 10

8.1 INTRODUCCIÓN ......................................................................................... 10

8.2 ALGUNOS CONSEJOS ANTES DE COMENZAR ........................................ 10

8.3 PRERREQUISITOS ......................................................................................... 11

8.4 IMPLEMENTACIÓN DEL MÉTODO NATIVO EN LENGUAJE ASM ............ 12

8.5 COMPILACIÓN CON MASM32 ................................................................. 13

8.6 ENLACE ........................................................................................................ 13

8.7 EJECUCIÓN ................................................................................................... 13

9. FUNCIONES UTILES DE LA JNI ............................................................ 14

10. GLOSARIO DE TERMINOS .................................................................... 14

APENDICE A: LIBRERÍAS ......................................................................... 15

APENDICE B: MACROENSAMBLADOR ........................................... 18

APENDICE C: CONFIGURACION DE VARIABLES DE

ENTORNO .............................................................................................................. 21

BIBLIOGRAFÍA ..................................................................................................... 24

Page 4: Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador

Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador.

Page 3

1. GENERALIDADES

1.1 Introducción.

Este manual surgió de la necesidad de transmitir el conocimiento adquirido

durante la realización del proyecto final de la materia de Lenguaje

Ensamblador.

El presente manual también pretende transmitir la estructura, conceptos e

información básica de la Interfaz Nativa de Java, con la finalidad de que

conociendo su funcionamiento, aquellos quienes sigan este manual, puedan

implementar sus programas de manera efectiva. Por lo mencionado, es de

suma importancia, leer el manual que se detalla a continuación antes y

durante el proceso de desarrollo.

El manual comienza explicando las ideas básicas acerca de la programación

híbrida y como sus aplicaciones, después de ello plantea una explicación del

funcionamiento de la Interfaz Nativa de Java, para luego ir explicando uno a

uno los pasos a seguir para llevar a cabo la implementación de funciones

nativas escritas en lenguaje Ensamblador.

Finalmente, se incluye un glosario con la terminología utilizada con la

finalidad de hacer más entendible este material.

1.2 Objetivos.

El principal objetivo del presente manual, es brindar información detallada

del proceso de integración de los lenguajes de programación antes

mencionados. Así mismo se pretende que el lector tenga una idea clara del

alcance que tiene dicha integración a través de la explicación ilustrada de

cada paso del proceso.

1.3 A quien va dirigido el manual.

Este manual va dirigido a cualquier entusiasta de la programación que tenga

nociones del lenguaje Java y esté familiarizado con conceptos del lenguaje

Ensamblador, así como académicos que quieran aplicar estos conocimientos

para la realización de sesiones prácticas relacionas con el tema o como

material meramente didáctico.

1.4 Acrónimos, anglicismos y abreviaturas empleadas.

API Application Programming Interface (Interfaz de

Programación de Aplicaciones).

ASM Assembly (Ensamblador).

COFF Common Object File Format (Formato de Archivo Objeto

Común)

IDE Integrated Development Environment

JASM Hibridación Java-ASM.

JDK Java Development Kit (Kit de Desarrollo de Java)

JNI Java Native Interface (Interfaz Nativa de Java).

LAN Local Area Network (Red de Área Local)

Linker Enlazador.

MP Microprocesador

pe. por ejemplo

Runtime Tiempo de ejecución.

TCP/IP Protocolo de Internet

Page 5: Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador

Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador.

Page 4

2. EL LENGUAJE JAVA

2.1 ¿Qué es Java?

Java es un lenguaje de programación orientado a

objetos, desarrollado por Sun Microsystems en 1996 y

diseñado por James Gosling (Fig 1). El lenguaje en sí

mismo toma mucha de su sintaxis de C y C++, pero

tiene un modelo de objetos más simple y elimina

herramientas de bajo nivel, que suelen inducir a muchos

errores, como la manipulación directa de punteros o

memoria. Con respecto a la memoria, su gestión no es

un problema ya que ésta es gestionada por el propio

lenguaje y no por el programador.

Las aplicaciones Java están típicamente compiladas en

un bytecode, aunque la compilación en código máquina

nativo también es posible. En el tiempo de ejecución, el

bytecode es normalmente interpretado o compilado a

código nativo para la ejecución, aunque la ejecución

directa por hardware del bytecode por un procesador Java

también es posible.

El término Java fue acuñado en una cafetería frecuentada

por algunos de los miembros del equipo. Pero no está

claro si es un acrónimo o no, aunque algunas fuentes

señalan que podría tratarse de las iniciales de sus

creadores: James Gosling, Arthur Van Hoff, y Andy

Bechtolsheim. Otros abogan por el siguiente acrónimo,

Just Another Vague Acronym ("sólo otro acrónimo

ambiguo más"). La hipótesis que más fuerza tiene es la

que Java debe su nombre a un tipo de café disponible en

la cafetería cercana, de ahí que el icono de java sea una taza de café caliente

(Fig. 2).

3. EL LENGUAJE ENSAMBLADOR

3.1 Ensamblador

Los ensambladores como los descritos en este trabajo son como una

versión reducida y elemental de un compilador (pero que de ninguna

manera deben considerarse como tales), ya que lo único que tienen que

hacer es cambiar toda referencia simbólica por la dirección

correspondiente, calcular los saltos, resolver referencias y llamadas a otros

programas, y realizar el proceso de enlace. Los ensambladores son

programas destinados a realizar el ensamblado de un determinado código.

3.2 Enlazador

Para crear un programa ejecutable a partir de un código objeto se requiere

que se resuelvan las llamadas a otros programas y a los servicios del sistema

operativo, y agregar las rutinas o información de run−time para que el

programa pueda ser cargado a memoria y ejecutado. Este proceso es lo que

se conoce como proceso de liga, y se realiza a través de un ligador,

enlazador o linker que toma de entrada el código objeto y produce de salida

el código ejecutable.

3.3 Generalidades del Lenguaje

El único lenguaje que entienden los microprocesadores y

microcontroladores, es el código máquina formado por ceros y unos del

sistema binario.

El lenguaje ensamblador expresa las instrucciones de una forma más natural

al hombre a la vez que muy cercana al MP, ya que cada una de esas

instrucciones se corresponde con otra en código máquina. El lenguaje

ensamblador trabaja con nemónicos, que son grupos de caracteres

alfanuméricos que simbolizan las órdenes o tareas a realizar.

Figura 1 James Gosling, trabajó

durante 18 meses en Sand Hill Road en Menlo Park en el

desarrollo de Java

Figura 2 Los 4 primeros bytes de

los archivos .class que

genera el compilador de java, son en

hexadecimal, 0xCAFEBABE.

Page 6: Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador

Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador.

Page 5

El programa escrito en lenguaje ensamblador se denomina código fuente

(*.asm). El programa ensamblador proporciona a partir de este fichero el

correspondiente código máquina, que suele tener la extensión (*.hex).

4. UTILIDAD DE LA PROGRAMACIÓN HÍBRIDA

4.1 Caso General

Hay ocasiones en que es necesario acceder a un nivel más bajo por razones

de operatividad e incluso de necesidad pe.

- Programas residentes que economicen memoria.

- Algoritmos rápidos para operaciones críticas.

- Parches (funciones no soportadas en LANs).

- etc.

La importancia del estudio de técnicas de hibridación de lenguajes radica en

la posible reutilización de código escrito en un lenguaje de bajo nivel o

cualquier otro.

4.2 Caso Particular

En el caso de Java y Ensamblador se pretende acceder a características no

disponibles para la tecnología Java pe. OpenCL, API gráfica, gestión de

nombres cortos en Windows, etc.

Igualmente a veces es conveniente implementar ciertas partes de la

aplicación en ASM por eficiencia pe.

- En el tratamiento de imágenes

- Transcodificadores de vídeo

- En casos en los que quiera cargar una librería nativa en un proceso

existente para evitar el costo de iniciar un nuevo proceso y cargar

la librería en el mismo

- Si se quiere implementar porciones de código en un lenguaje de

bajo nivel como ensamblador para disminuir el tiempo de

procesamiento. Por ejemplo, en aplicaciones que necesiten

renderizar gráficos 3D que requieren más tiempo de

procesamiento, habrá que escribir una librería para gráficos en

lenguaje ensamblador para tener un mejor rendimiento.

- etc.

También se intenta aprovechar las más poderosas características del

lenguaje ASM tales como la de explotar las capacidades del hardware de la

computadora a bajo nivel en forma eficiente, la velocidad a la que se

procesan las instrucciones codificadas en este lenguaje y su flexibilidad,

puesto que todo lo que puede hacerse con una máquina, puede hacerse en

el lenguaje ensamblador de esta máquina.

6. ENTORNOS DE DESARROLLO

6.1 Eclipse

Eclipse (Fig. 3) es un entorno de

desarrollo integrado de código

abierto multiplataforma para

desarrollar lo que el proyecto

llama "Aplicaciones de Cliente

Enriquecido", opuesto a las

aplicaciones "Cliente-liviano"

basadas en navegadores. Esta

plataforma, típicamente ha sido

usada para desarrollar entornos

de desarrollo integrados, como el

IDE de Java llamado Java Development Toolkit (JDT, que se entrega como

parte de Eclipse. Sin embargo, también se puede usar para otros tipos de

aplicaciones cliente, como BitTorrent o Azureus.

Figura 3 Spash Screen de la plataforma Eclipse.

Page 7: Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador

Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador.

Page 6

6.2 Netbeans

NetBeans (Fig. 4) es un entorno de desarrollo integrado libre, hecho

principalmente para el lenguaje de programación Java. Existe además un

número importante de módulos para extenderlo. NetBeans IDE es un

producto libre y gratuito sin restricciones de uso.

Figura 4 Splash Screen del IDE Netbeans

El IDE NetBeans es un entorno de desarrollo integrado - una herramienta

para programadores pensada para escribir, compilar, depurar y ejecutar

programas. Está escrito en Java - pero puede servir para cualquier otro

lenguaje de programación. Existe además un número importante de

módulos para extender el IDE NetBeans. El IDE NetBeans es un producto

libre y gratuito sin restricciones de uso.

6.3 MASM32

El Microsoft Macro Assembler (MASM) es un ensamblador para la familia

x86 de microprocesadores. Fue producido originalmente por Microsoft

para el trabajo de desarrollo en su sistema operativo MS-DOS, y fue

durante cierto tiempo el ensamblador más popular disponible para ese

sistema operativo. El MASM soportó una amplia variedad de facilidades para

macros y programación estructurada, incluyendo construcciones de alto

nivel para bucles, llamadas a procedimientos y alternación (por lo tanto,

MASM es un ejemplo de un ensamblador de alto nivel). Versiones

posteriores agregaron la capacidad de producir programas para los sistemas

operativos Windows. MASM es una de las pocas herramientas de desarrollo

de Microsoft para las cuales no había versiones separadas de 16 bits y 32

bits.

El proyecto MASM32 [10] ha puesto juntos una muy impresionante librería

de programador, un repositorio de ejemplos de código, y una

extraordinaria documentación para los usuarios del MASM. MASM también

es soportado por una gran cantidad de páginas web y foros de discusión [9].

A pesar de la edad de este producto, sigue siendo uno de los

ensambladores en existencia mejor soportados.

7. JAVA NATIVE INTERFACE

7.1 Introducción

Java Native Interface es una característica de Java que permite incorporar

en aplicaciones Java código escrito en lenguaje C o C++, incluso ASM

(también Java, cuando es llamado desde aplicaciones escritas en C).JNI es

parte de la máquina virtual Java y permite invocaciones en ambos sentidos:

aplicaciones Java pueden invocar código nativo escrito en otro lenguaje y

viceversa.

Podemos usar JNI para escribir métodos nativos. Éstos tienen prototipo en

Java pero su implementación es hecha en otro lenguaje. Estas

implementaciones son pasadas a la máquina virtual a través de bibliotecas

nativas (.dll en Windows o .so en Linux) Ver tope de la Figura 3.

Page 8: Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador

Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador.

Page 7

JNI también soporta una interfaz nativas permite incrustar una

implementación de la máquina virtual dentro de aplicaciones nativas (fondo

de la Figura 3). Aplicaciones nativas pueden enlazarse con una biblioteca

nativa que implementa la máquina virtual Java y luego usar la interfaz de

invocación para ejecutar componentes escritas en lenguaje Java. Así es

cómo un navegador escrito en C puede ejecutar applets en una máquina

virtual embebida

7.2 ¿Cuándo usar JNI?

Hay dos efectos secundarios del uso de JNI: Las aplicaciones que dependen

de métodos nativos dejan de correr en otros ambientes. Se hace necesario

re-hacer la biblioteca para cada ambiente. En segundo lugar se pierden

algunas características del lenguaje. Un mal comportamiento de un método

nativo afecta toda la aplicación. ¿Qué pasa si el método nativo genera fuga

de memoria? Como regla general se debe limitar el uso de métodos nativos

a un mínimo.

Se recomienda usar JNI cuando la aplicación requiere alguna característica

del host no accesible a través de la máquina virtual, cuando se desea

acceder a bibliotecas nativas, o cuando deseamos dar mayor velocidad a

porciones críticas del código.

Existen alternativas a JNI que implican comunicación entre procesos. Por

ejemplo, cuando usamos la clase Runtime para ejecutar procesos nativos en

forma concurrente. También podemos comunicar procesos vía TCP/IP, usar

tecnologías para distribuir objetos como la API de Java IDL. En todos estos

casos se sacrifica eficiencia por la necesaria comunicación entre procesos.

7.3 Usando JNI para invocar métodos nativos

En general el uso es simple, la mayor atención se debe poner en el paso de

parámetros entre el método en Java y su implementación en C. Los pasos a

seguir se resumen en la Figura 4.

Figura 6 Pasos para incluir métodos nativos en una aplicación Java.C

A través de un ejemplo simple veremos estos pasos uno a uno.

Crear una Clase que Implementa el método nativo.

• Archivo.java

Usar javac para compilar el programa.

• Archivo.class

Usar javah para generar arcivo encabezado.

• Archivo.h

Escribir la implementación C del metodo nativo.

• Archivo.c

Compilar y generar la biblioteca .(dll .so).

• Archivo.dll

Correr usando el interpréte java.

Aplicación Java y

Biblioteca

yy

Host

Implementación

de la Máquina

Virtual Java

JNI

Aplicación Nativa y

Biblioteca

yy Figura 5Usos de JNI, Aplicación Java más biblioteca puede correr sobre el host a través de la JVM, o una Aplicación Nativa más una biblioteca puede correr sobre el host.

Page 9: Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador

Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador.

Page 8

1. Creación de una clase que declara un método nativo.

Abrimos nuestro editor de texto y pegamos el siguiente segmento de

código, a continuación lo guardamos con el nombre de la clase (Hello.java).

//Fichero: Hello.java

class Hello {

public native void sayHello();

static {

System.loadLibrary("hello");

}

public static void main(String[] args) {

Hello h = new Hello();

h.sayHello ();

}

}

En este ejemplo el modificador native del método sayHello le indica al

compilador de java que dicho método estará escrito en otro lenguaje

(llamado nativo) por lo que buscara la implementación asociada a este en

la(s) librería(s) ubicadas en el mismo directorio de nuestro archivo .java

2. Compilación usando el comando javac en MS-DOS.

Abrimos una instancia de la terminal y valiéndonos del comando cd nos

posicionamos en el directorio de trabajo (en donde se encuentra el archivo

.java previamente guardado) a continuación tecleamos la siguiente

instrucción:

Se generará un archivo llamado Hello.class.

3.- Creación del encabezado del método nativo.

En la misma instancia de consola tecleamos:

Se generará un fichero de cabecera llamado Hello.h. En este caso su

contenido esencial es:

La implementación C del método tiene un nombre que alude al código Java

de origen, nombre de la clase y nombre del método. Aun cuando el método

Java no tiene argumentos, su implementación considera dos. El primer

argumento de toda implementación de método nativo es un puntero a

JNIEnv, el segundo es una referencia al objeto Hello mismo (como el

puntero a this en C++).

4.- Implementación del método nativo.

Procedemos a implementar la funcionalidad del método nativo en un

archivo asociado al lenguaje apropiado, en nuestro ejemplo, lenguaje C, de

la siguiente manera.

#include <jni.h>

#include <stdio.h>

#include "Hello.h"

// JNIEXPORT y JNICALL corresponde a macros requeridas, en medio

el tipo retornado.

JNIEXPORT void JNICALL Java_Hello_sayHello (JNIEnv *env, jobject

obj) {

printf("Hello World!\n");

return;

}

int main() {

return 0;

}

JNIEXPORT void JNICALL Java_Hello_sayHello(JNIEnv *, jobject);

C:\> javah -jni Hello

C:\>javac Hello.java

Page 10: Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador

Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador.

Page 9

No olvidar codificar la función main si trabajamos en el ambiente Dev-C++

ya que de otra forma no se compilara correctamente el fichero.

Se debe incluir encabezados según la implementación que hagamos. El

código es C convencional.

5.- Compilación del código C y creación de la biblioteca de

ligado dinámico.

Esto depende del sistema operativo nativo. En este caso será Windows.

Para el compilador gcc (el mismo usado por Dev-C++) primero creamos el

archivo objeto, la sintaxis es:

El parámetro -I agrega dos rutas a nuestro rutas de inclusión estándar, para

que el compilador pueda accesar a los archivos cabecera de la JNI. Las rutas

son <java install dir>\include y <java install dir>\include\win32, donde <java

install dir> es reemplazado por el directorio en el que se encuentra

instalado el JDK. Si la ruta contiene espacios debera ser rodeada por

comillas dobles por claridad (para el lector y el compilador).

Una vez hecho esto procedemos a escribir un archivo de definiciones (.def)

especificando las funciones que serán exportadas, este fichero es usado por

el compilador al momento de crear la dll y tiene el siguiente

formato:

En nuestro caso el contenido seria

este:

Una vez creado este archivo procedemos a ejecutar lo siguiente para la

creación de la dll.

Este otro comando funciona con Microsoft Visual C++ 5.0 y genera la

librería dinámica directamente:

Con otros compiladores puede ser diferente; el lector deberá consultar el

manual del compilador para conocer los parámetros apropiados.

Como resultado en cualquiera de los casos se generará la biblioteca hello.dll

Si se quiere indicar al compilador donde se encuentran los ficheros

cabecera y las bibliotecas, se deben fijar dos variables de entorno (refiérase

al apéndice C para más información acerca de las variables de entorno):

Donde %JAVAHOME% es el directorio donde se ha instalado la plataforma

Java 2, o alguna versión del JDK.

6.- Ejecución de la aplicación

Podemos ejecutar la aplicación mediante la siguiente instrucción:

C:\>java HelloWorld

C:\>SET INCLUDE = %JAVAHOME%\include;%INCLUDE% C:\>SET LIB = %JAVAHOME%\lib;%LIB%

cl Hello.c -Fhello.dll -LD

gcc -shared -o hello.dll hello.o hello.def

EXPORTS Java_Hello_sayHello

EXPORTS < nombre_ función_1> < nombre_función_2> … < nombre_función_n>

gcc -c -I"C:\jdk1.x\include" -I"C:\jdk1.x\include\win32" -o hello.o Hello.c

Page 11: Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador

Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador.

Page 10

El resultado de hacer esto sería:

Java también admite especificar el directorio de la biblioteca con la opción -

Djava.library.path, en este caso:

8. EJEMPLO DE JASM

8.1 Introducción

Como hemos visto en ejemplos anteriores resulta ser relativamente sencillo

lograr la correcta hibridación de aplicaciones Java con C como lenguaje

nativo, pero nuestro objetivo es el de lograrlo usando un enfoque distinto,

me refiero a utilizar ASM como lenguaje nativo.

Recurrir a los libros en busca de ejemplos concretos y bien detallados de

JASM es meramente una pérdida de tiempo pues en lo que a mí respecta,

no hay.

Buscando en Internet se pueden encontrar algunos (escasos) ejemplos de

JASM el principal inconveniente de estos es que no profundizan mucho en

el tema siendo ejemplos meramente triviales, otro de los inconvenientes es

que en su mayoría están en Ingles y por lo tanto se requiere de una

esfuerzo más grande el comprenderlos a cabalidad.

Es por esto que escribo este manual, para que aquellos a quienes les

interese JASM encuentren la pauta que buscan para desarrollar un camino

favorable en sus proyectos ya sea personales, profesionales o académicos.

Espero poder mejorar continuamente este material incorporando nuevos

conceptos y corrigiendo posibles fallas en él, así como recibir consejos y

sugerencias acerca de este documento.

El Autor.

8.2 Algunos Consejos Antes de Comenzar

Primero que nada sugiero revisar detenidamente cada uno de los apéndices,

en los que se incluye información útil acerca del entorno general en el que

trabajaremos.

Se sugiere la el uso de un makefile, o archivo por lotes ejecutable (.bat) es

decir un archivo conteniendo en orden los comandos necesarios para la

compilación y enlace de nuestro proyecto. Para este ejemplo el archivo por

lotes seria:

Guardamos como make.bat

@ECHO OFF Indica que solo se mostrarán los resultados de los

comandos usados en este archivo.

Nos aseguramos que no exista un archivo previo con el nombre

Operadores.obj u OperadoresDLL.dll

IF EXISTS Operadores.obj DEL Operadores.obj

IF EXISTS OperadoresDLL.dll DEL OperadoresDLL.dll

Borramos los archivos que no necesitaremos una vez que se haya

compilado correctamente nuestro código.

DEL Operadores.obj

DEL Operadores.exp

/nologo Evita la impresión los logotipos del ml y link.

@ECHO OFF CD "Desktop" javac Calculadora.java javah -jni Calculadora IF EXISTS Operadores.obj DEL Operadores.obj IF EXISTS OperadoresDLL.dll DEL OperadoresDLL.dll ml /c /coff /Cp /nologo Operadores.asm link /DLL /NOENTRY /subsystem:windows /nologo /DEF:OperadoresDLL.def Operadores.objOperadores.obj DEL Operadores.obj DEL Operadores.exp java Calculadora PAUSE

C:\>java -Djava.library.path = C:\directorio-de-la biblioteca\ HelloWorld

Hello World!

Page 12: Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador

Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador.

Page 11

Más a delante daremos una explicación de los parámetros de los comandos

ml y link.

Es importante recordar que:

I. Hay que tener cuidado con el uso de los registros del MP ya que

podría haber inconvenientes con el sistema en el que estemos

desarrollando aplicaciones.

II. Avanzaremos a partir del paso “4. Implementación del método

nativo.” del apartado anterior que es donde nuestro enfoque se

separa de este ejemplo.

III. El lenguaje ASM está íntimamente relacionado con la arquitectura

del MP con el que cuente nuestra computadora.

IV. Por lo anterior las aplicaciones pueden no ser exportables a otros

sistemas (al menos no sin hacer las correcciones adecuadas)

V. Es una buena práctica documentar cada módulo de nuestro

programa ya sea en Java o ASM.

VI. Otra buena práctica de programación en ASM es la de escribir

entre comentarios como se verían nuestras funciones si

estuviéramos programando en C o Java.

VII. Nada es impensable para la inteligencia humana.

8.3 Prerrequisitos

Se sugiere por practicidad, que se sigan los pasos descritos en el Apéndice

C para la configuración de las variables de entorno de Java y MASM32.

Abriremos ya sea nuestro editor de texto o IDE para escribir una clase

Java que debe verse como sigue:

public class Calculadora {

public native int sumar(int a, int b);

public native int restar(int a, int b);

public native int multiplicar(int a, int b);

public native int ElevarAlCuad(int a);

public native double RaizCuad(int a);

static {

System.loadLibrary("Operadores");

}

public static void main(String[] args) {

int x = 11;

int y = 6;

Calculadora op = new Calculadora();

int resultadoInt = op.sumar(x, y);

System.out.println("El resultado de la suma es: " +

resultadoInt);

resultadoInt = op.restar(x, y);

System.out.println("El resultado de la resta es: " +

resultadoInt);

resultadoInt = op.multiplicar(x, y);

System.out.println("El resultado de la multiplicación

es: " + resultadoInt);

resultadoInt = op.ElevarAlCuad(x);

System.out.println("El resultado de la elevar x al

cuadrado es: " + resultadoInt);

double resultado = op.RaizCuad(y);

System.out.println("La raiz cuadrada de 'y' es: " +

resultado);

}

}

Page 13: Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador

Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador.

Page 12

En este ejemplo crearemos una calculadora con operaciones aritméticas

básicas. Primero llevaremos a cabo los 3 primeros pasos del ejemplo del

apartado anterior sobre esta clase.

8.4 Implementación del Método Nativo en Lenguaje ASM

Una vez que tengamos el fichero cabecera, procedemos a crear el archivo

de definiciones como sigue:

No olvidemos que aqui hay que hacer referencia a TODOS los métodos

nativos que queramos que se incluyan en la librería dinámica, ya que un

posible error sería que nustro programa no encuentre algún método no

considerado en este fichero.

Lo guardamos con el nombre de OperadoresDLL.def y a continuación

escibiremos nuetra implementación de estas funciones:

.686

.model flat,stdcall

.code

Java_Calculadora_sumar proc JNIEnv:DWORD, jclass:DWORD, x:DWORD,

y:DWORD

mov eax, x

mov ebx, y

add eax, ebx ;sumamos el contenido del registro eax al

de ebx

ret

Java_Calculadora_sumar endp

Java_Calculadora_restar proc JNIEnv:DWORD, jclass:DWORD,

x:DWORD, y:DWORD

mov eax, x

mov ebx, y

sub eax, ebx ;restamos el contenido del registro eax al

de ebx

ret

Java_Calculadora_restar endp

Java_Calculadora_multiplicar proc JNIEnv:DWORD, jclass:DWORD,

x:DWORD, y:DWORD

mov eax, x

mov ebx, y

mul ebx ;multiplicamos el contenido del registro ebx con

el registro por default eax

ret

Java_Calculadora_multiplicar endp

Java_Calculadora_ElevarAlCuad proc JNIEnv:DWORD, jclass:DWORD,

x:DWORD

PUSH x

PUSH x

PUSH jclass

PUSH JNIEnv

call Java_Calculadora_multiplicar ;elevamos al cuadrado

x valiéndonos del procedimiento Java_Calculadora_multiplicar

ret

Java_Calculadora_ElevarAlCuad endp

Java_Calculadora_RaizCuad proc JNIEnv:DWORD, jclass:DWORD,

x:DWORD

LOCAL S:REAL4 ; Declaramos una variable de ambito local

; y de tipo real de 4 bytes

; Funciones del Coprocesador Matemático

fild x ; Cargamos el valor del parametro x

fsqrt ; Hallamos la raiz cuadrada

fst S ; Almacenamos el resultado en S

mov eax, S ; Transferimos el contenido de S a eax

ret

Java_Calculadora_RaizCuad endp

END

.686 Define el conjunto de instrucciones que estaremos usando, aquí 80386

.model flat Indica que estaremos usando un tipo de memoria protegida

plana de 32bits que es el que usa el 686 (Pentium Dual Core)

stdcall Define el orden en que se van a pasar los parámetros (izquierda a

derecha o derecha a izquierda)

EXPORTS Java_Calculadora_sumar Java_Calculadora_restar Java_Calculadora_multiplicar Java_Calculadora_ElevarAlCuad

Page 14: Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador

Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador.

Page 13

Java_Calculadora_sumar proc JNIEnv:DWORD, jclass:DWORD,

x:DWORD, y:DWORD

Aquí podemos ver la declaración de nuestro procedimiento donde se define

que se llamará Java_Operaciones_sumar, tal como lo vimos antes, y tendrá

cuatro parámetros. Aquí podemos nombrar a nuestros parámetros como

nos plazca, pero debemos tener en cuenta el orden en el que aparecen y el

tipo de dato, en nuestro caso los parámetros que nos importan se llaman x

e y.

El resto es el código ASM que realizará la tarea que deseamos, en este caso

sumar x e y.

ret Al terminar de ejecutarse nuestro código, se hará un return que

devolverá el contenido del registro por default eax, por eso no se indica

explícitamente. El valor del registro eax será el que capturará el programa

Java y lo mostrará en la salida de pantalla.

Como habremos podido notar las funciones en ASM tienen una estructura

parecida una función en C, las ultimas 2 que hemos implementado son de

interés particular pues en la función Java_Calculadora_ElevarAlCuad

nos valemos de la función Java_Calculadora_multiplicar para calcular el

valor de retorno, Nótese que los parámetros son apilados en orden inverso

antes de realizar la llamada a la función mediante la directiva call.

La siguiente función a estudiar es Java_Calculadora_RaizCuad en ella

hacemos uso de una poderosa herramienta de cálculo matemático: El

Coprocesador, a través de la instrucción fild almacenamos el valor de x en

la pila del coprocesador, a continuación hallamos su raíz cuadrada por

medio de la instrucción fsqrt, luego salvamos este valor en S, una variable

local previamente definida que es del tipo apropiado para almacenar valores

de punto flotante con doble precisión después movemos el contenido de S

al registro eax para ser retornado a la clase Calculadora para su

despliegue.

Guardamos este código como Operadores.asm

8.5 Compilación con MASM32

Procederemos a compilar el código ASM con el ensamblador MAS32 (Si aún

no se han definido las variables de entorno para el comando ml refiérase al

Apéndice C donde se detallan los pasos a seguir para configurar el entorno

Java y MASM32. Luego entonces escribimos en consola:

ml Es el programa de MASM32 para crear el objeto

/c le indicamos que solo habrá de ensamblar el archivo .obj

/coff para indicar que el objeto ensamblado tendrá el formato COFF

/Cp indicará a MASM32 que será sensible a mayúsculas y minúsculas de los

identificadores que se usen

8.6 Enlace

El comando a ejecutar es el siguiente:

link el programa (enlazador) que usaremos para generar el .dll

/DLL indica que lo que queremos generar es un DLL

/NOENTRY para poder evitar algunos posibles errores no capturados

/SUBSYSTEM:windows indicamos que el ejecutable es para windows

/DEF:archivo.def y el archivo de definición que se usará para la exportación

Finalmente indicamos el nombre de nuestro archivo ensamblado,

Operadores.obj

8.7 Ejecución

Ejecutamos el programa así:

Java Hello

link /DLL /NOENTRY /subsystem:windows /DEF:OperadoresDLL.def Operadores.obj

ml /c /coff /Cp Operadores.asm

Page 15: Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador

Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador.

Page 14

Y el resultado será este:

9. FUNCIONES UTILES DE LA JNI

10. GLOSARIO DE TERMINOS

Applet - Un applet es un componente de una aplicación que se ejecuta en el contexto de otro

programa, por ejemplo un navegador web. El applet debe ejecutarse en un contenedor, que lo

proporciona un programa anfitrión, mediante un plugin, o en aplicaciones como teléfonos

móviles que soportan el modelo de programación por 'applets'.

Bytecode - El bytecode es un código intermedio más abstracto que el código máquina.

Habitualmente es tratado como un fichero binario que contiene un programa ejecutable similar a

un módulo objeto, que es un fichero binario producido por el compilador cuyo contenido es el código objeto o código máquina.

Compilación - Es el proceso por el cual se traducen las instrucciones escritas en un

determinado lenguaje de programación a lenguaje máquina. Además de un traductor, se pueden

necesitar otros programas para crear un programa objeto ejecutable. Un programa fuente se puede dividir en módulos almacenados en archivos distintos. La tarea de reunir el programa

fuente a menudo se confía a un programa distinto, llamado preprocesador. El preprocesador

también puede expandir abreviaturas, llamadas a macros, a proposiciones del lenguaje fuente.

Compilador - Un compilador es un programa informático que traduce un programa escrito

en un lenguaje de programación a otro lenguaje de programación, generando un programa

equivalente que la máquina será capaz de interpretar. Usualmente el segundo lenguaje es

lenguaje de máquina, pero también puede ser un código intermedio (bytecode), o simplemente

texto. Este proceso de traducción se conoce como compilación.

Consola - Interfaz de Línea de Comandos (CLI), por su acrónimo en inglés de Command

Line Interface (CLI), es un método que permite a las personas dar instrucciones a algún programa informático por medio de una línea de texto simple. Debe notarse que los conceptos

de CLI, Shell y Emulador de Terminal no son lo mismo, aunque suelen utilizarse como

sinónimos.

Depurar - Depuración de programas es el proceso de identificar y corregir errores de

programación. En inglés se le conoce como debugging, ya que se asemeja a la eliminación de

bichos (bugs), manera en que se conoce informalmente a los errores de programación.

Host - El término host es usado en informática para referirse a las computadoras conectados a

una red, que proveen y utilizan servicios de ella. Los usuarios deben utilizar hosts para tener

acceso a la red. En general, los hosts son computadores monousuario o multiusuario que ofrecen

servicios de transferencia de archivos, conexión remota, servidores de base de datos, servidores web, etc. Los usuarios que hacen uso de los hosts pueden a su vez pedir los mismos servicios a

otras máquinas conectadas a la red. De forma general un host es todo equipo informático que

posee una dirección IP y que se encuentra interconectado con uno o más equipos.

Biblioteca (Librería) - En ciencias de la computación, una biblioteca (del inglés library)

es un conjunto de subprogramas utilizados para desarrollar software. Las bibliotecas contienen

código y datos, que proporcionan servicios a programas independientes, es decir, pasan a formar

parte de éstos. Esto permite que el código y los datos se compartan y puedan modificarse de forma modular. Algunos programas ejecutables pueden ser a la vez programas independientes y

bibliotecas, pero la mayoría de éstas no son ejecutables. Ejecutables y bibliotecas hacen

referencias (llamadas enlaces) entre sí a través de un proceso conocido como enlace, que por lo general es realizado por un software denominado enlazador.

GNU/Linux - Es uno de los términos empleados para referirse a la combinación del núcleo

o kernel libre similar a Unix denominado Linux, que es usado con herramientas de sistema GNU. Su desarrollo es uno de los ejemplos más prominentes de software libre; todo su código

fuente puede ser utilizado, modificado y redistribuido libremente por cualquiera bajo los

términos de la GPL (Licencia Pública General de GNU, en inglés: General Public License) y otra serie de licencias libres.

OpenCL - OpenCL (Open Computing Language, en español lenguaje de computación

abierto) consta de una interfaz de programación de aplicaciones y de un lenguaje de programación. Juntos permiten crear aplicaciones con paralelismo a nivel de datos y de tareas

que pueden ejecutarse tanto en unidades centrales de procesamiento como unidades de

procesamiento gráfico. El lenguaje está basado en C99, eliminando cierta funcionalidad y extendiéndolo con operaciones vectoriales.

Renderizar

Runtime - Se denomina tiempo de ejecución (runtime en inglés) al intervalo de tiempo en el

que un programa de computadora se ejecuta en un sistema operativo. Este tiempo se inicia con la puesta en memoria principal del programa, por lo que el sistema operativo comienza a

ejecutar sus instrucciones. El intervalo finaliza en el momento en que éste envía al sistema

operativo la señal de terminación, sea ésta una terminación normal, en que el programa tuvo la posibilidad de concluir sus instrucciones satisfactoriamente, o una terminación anormal, en el

que el programa produjo algún error y el sistema debió forzar su finalización.

Subrutina - En computación, una subrutina o subprograma (también llamada procedimiento,

función o rutina), como idea general, se presenta como un subalgoritmo que forma parte del algoritmo principal, el cual permite resolver una tarea específica. Algunos lenguajes de

programación, como Visual Basic .NET o Fortran, utilizan el nombre función para referirse a

subrutinas que devuelven un valor.

Terminal - Un terminal, conocido también como consola es un dispositivo electrónico o

electromecánico de hardware, usado para introducir o mostrar datos de una computadora o de un

sistema de computación.

El resultado de la suma es: 17 El resultado de la resta es: 5 El resultado de la multiplicacion es: 66 El resultado de la elevar al cuadrado es: 121

Page 16: Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador

Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador.

Page 15

Transcodificar - Se denomina transcodificar (del inglés transcoding) a la conversión

directa (de digital a digital) de un códec a otro. Puede ser con o sin pérdida de calidad,

dependiendo del codec usado.

Esta operación implica decodificar/descomprimir los datos originales a un formato crudo (RAW

data) intermedio (por ejemplo, PCM para audio o YUV para vídeo), de manera que los imite, y

luego recodificarlos para alcanzar el códec deseado.

Unix - Registrado oficialmente como UNIX®, es un sistema operativo portable, multitarea y

multiusuario; desarrollado, en principio, en 1969 por un grupo de empleados de los laboratorios

Bell de AT&T, entre los que figuran Ken Thompson, Dennis Ritchie y Douglas McIlroy.

APENDICE A: LIBRERÍAS

INTRODUCCIÓN

Según vamos haciendo programas de ordenador, nos damos cuenta que

algunas partes del código se utilizan en muchos de ellos. Por ejemplo,

podemos tener varios programas que utilizan números complejos y las

funciones de suma, resta, etc. son comunes.

USO DE LIBRERÍAS

Sería estupendo poder tener esas funciones en un directorio separado de

los programas concretos y tenerlas previamente compiladas, de forma que

podamos usarlas siempre que queramos.

Las ventajas enormes de esto son:

a. No tener que volver a escribir el código (o hacer copy-paste).

b. Ahorro de tiempo de compilación puesto que este código ya está

compilado. Además, ya sabemos que mientras hacemos un

programa, probamos y corregimos, hay que compilar entre muchas

y "muchas más" veces.

c. El código ya compilado estará probado y será fiable. No las

primeras veces, pero sí cuando ya lo hayamos usado en una gran

cantidad de programas distintos y le hayamos corregido los

errores.

La forma de hacer esto es la creación de librerías. Una librería es en esencia

una o más funciones que tenemos ya compiladas y preparadas para ser

utilizadas en cualquier programa que hagamos. Hay que tener el suficiente

cuidado cuando las creamos para no involucrar ninguna dependencia de algo

concreto de nuestro programa.

CÓMO TENEMOS QUE ORGANIZAR NUESTRO CÓDIGO

Para poder implementar nuestro código en una librería, necesitamos

organizarlo de la siguiente manera:

- Uno o más ficheros fuente .c con el código de nuestras funciones.

- Uno o más ficheros de cabecera .h con los tipos (typedefs, structs

y enums) y prototipos de las funciones que vayamos a reutilizar.

Como es usual, vamos a hacer un ejemplo. Los ficheros serían estos:

Fichero libreria1.h #ifndef _LIBRERIA_1_H

#define _LIBRERIA_1_H

int suma (int a, int b);

int resta (int a, int b);

#endif

Fichero libreria1.c int suma (int a, int b) {

return a+b;

}

int resta (int a, int b) {

return a-b;

}

Un detalle importante a tener en cuenta, son los #define del fichero de

cabecera (.h). Al hacer una librería, no sabemos en qué futuros programas

la vamos a utilizar ni cómo estarán organizados.

Page 17: Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador

Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador.

Page 16

Pensemos en un futuro programa en el que hay un fichero de cabecera

fichero1.h que mediante la directiva #include hace referencia a nuestra

librería. Imaginemos que hay también un fichero2.h que también hace

inclusión de ella. Finalmente, con un pequeño esfuerzo más, imaginemos

que hay un tercer fichero3.c que hace incluye al fichero1.h y fichero2.h, es

decir, más o menos lo siguiente:

fichero1.h

#include <libreria1.h>

...

fichero2.h

#include <libreria1.h>

...

fichero3.c

#include <fichero1.h>

#include <fichero2.h>

...

Cuando compilemos fichero3.c, dependiendo de lo que haya definido en

libreria1.h, obtendremos un error. El problema es que al incluir fichero1.h, se

define todo lo que haya en ese fichero, incluido lo de libreria1.h. Cuando se

incluye fichero2.h, se vuelve a intentar definir lo contenido en libreria1.h, y se

obtiene un error de que esas definiciones están definidas dos veces.

La forma de evitar este problema, es meter todas las definiciones dentro de

un bloque #ifndef - #endif, (también conocido como bloque de

compilación condicional) con el nombre (_LIBRERIA_1_H en el ejemplo)

que más nos guste y distinto para cada uno de nuestros ficheros de

cabecera. Es habitual poner este nombre precedido de _, acabado en _H y

que coincida con el nombre del fichero de cabecera, pero en mayúsculas.

Dentro del bloque #ifndef - #endif, hacemos un #define de ese nombre

(no hace falta darle ningún valor, basta con que esté definido) y luego

definimos todos nuestros tipos y prototipos de funciones.

Cuando incluyamos este fichero por primera vez, _LIBRERIA_1_H no

estará definido, así que se entrará dentro del bloque #ifndef - #endif y se

definirán todos los tipos y prototipos de funciones, incluido el mismo

_LIBRERIA_1_H. Cuando lo incluyamos por segunda vez, _LIBRERIA_1_H

ya estará definido (de la inclusión anterior), por lo que no se entrará en el

bloque #ifndef - #endif, y no se redefinirá nada por segunda vez.

Es buena práctica hacer esto con todos nuestros .h, independientemente de

que sean o no para librerías. Si te fijas en algún .h del sistema verás que

tienes este tipo de cosas hasta aburrir. Por ejemplo, en /usr/include/stdio.h, lo

primero que hay después de los comentarios, es un #ifndef _STDIO_H.

LIBRERIAS ESTÁTICAS Y DINÁMICAS

Una librería estática es una librería que "se copia" en nuestro programa

cuando lo compilamos. Una vez que obtenemos el ejecutable de nuestro

programa, la librería no sirve para nada (es un decir, sirve para otros

futuros proyectos). Podríamos borrarla y nuestro programa seguiría

funcionando, ya que tiene copia de todo lo que necesita. Sólo se copia

aquella parte de la librería que se necesite. Por ejemplo, si la librería tiene

dos funciones y nuestro programa sólo llama a una, sólo se copia esa

función.

Una librería dinámica NO se copia en nuestro programa al compilarlo.

Cuando tengamos nuestro ejecutable y lo estemos ejecutando, cada vez que

el código necesite algo de la librería, irá a buscarlo a ésta. Si borramos la

librería, nuestro programa arrojará un error informándonos que no la

encuentra.

¿Cuáles son las ventajas e inconvenientes de cada uno de estos tipos de librerías?

Un programa compilado con librerías estáticas es más grande, ya que se

hace copia de todo lo que necesita.

Un programa compilado con librerías estáticas se puede llevar a otro

ordenador sin necesidad de llevarse las librerías.

Un programa compilado con librerías estáticas es, en principio, más rápido

en ejecución. Cuando llama a una función de la librería, la tiene en su código

y no tiene que ir a leer el fichero de la librería dinámica para encontrar la

función y ejecutarla.

Page 18: Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador

Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador.

Page 17

cc -o miprograma miprograma.c -I<path1> -I<path2> ... -

L<path1> -L<path2> ... -Bdynamic -llibreria1 -llibreria2

Si cambiamos una librería estática, a los ejecutables no les afecta. Si

cambiamos una dinámica, los ejecutables se ven afectados. Esto es una

ventaja si hemos cambiado la librería para corregir un error (se corrige

automáticamente en todos los ejecutables), pero es un inconveniente si

tocar eso nos hace cambiar los ejecutables (por ejemplo, hemos añadido un

parámetro más a una función de la librería, los ejecutables ya hechos dejan

de funcionar).

¿Qué tipo de librería uso entonces?

Es como siempre una cuestión de compromiso entre las ventajas y los

inconvenientes. Para programas no muy grandes y por simplicidad, suelen

usarse librerías estáticas. Las dinámicas están bien para programas enormes

o para librerías del sistema, que como están en todos los ordenadores con

sistema operativo Linux, no es necesario andar llevándoselas de un lado a

otro.

En sistemas Windows las librerías estáticas suelen llamarse nombre.lib y

las dinámicas nombre.dll (librería de enlace dinámico), donde „nombre‟ es el

nombre de nuestra librería.

En sistemas Unix las librerías estáticas suelen llamarse libnombre.a y las

dinámicas libnombre.so, donde „nombre‟ es el nombre de nuestra librería,

esta característica es heredada por todas las plataformas Linux.

CREACION DE LIBRERÍAS DINÁMICAS

Para compilar los mismos ficheros, pero como librería dinámica, tenemos

que seguir los siguientes pasos:

En sistemas Unix/Linux

1. Compilar los archivos fuente, igual que antes, para obtener los

objetos.

2. Crear la librería con el comando ld. Las opciones para este

comando serían:

La opción -o liblibreria.so le indica el nombre que queremos dar a la

librería. La opción -shared le indica que debe hacer una librería y no

un ejecutable (opción por defecto). objeto1.o, objeto2.o... son los

ficheros objeto que queremos incluir en la librería.

3. Una vez generada la librería, hay que enlazar con ella nuestro

programa.

4. Indicar al programa la localización de la o las librerías dinámicas.

En general podemos realizar el segundo paso para uno o más archivos

objeto:

La librería depende de los archivos fuente, los cuales se compilan para

obtener los .o (habría que añadir además las opciones -I<path> que fueran

necesarias), se construye la librería con ld y se borran los objetos

generados. Se ha hecho depender la librería de los archivos fuente para que

se compile sólo si se cambia un archivo fuente. Si se hace depender de los

objetos, como al final son borrados, siempre se recompilaría la librería.

Makefile

liblibreria.so: objeto1.c objeto2.c...

cc -c -o objeto1.o objeto1.c

cc -c -o objeto2.o objeto2.c

...

ld -o liblibreria.so objeto1.o objeto2.o ... -shared

rm objeto1.o objeto2.o ...

ld -o liblibreria.so objeto1.o objeto2.o... -shared.

Page 19: Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador

Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador.

Page 18

Para el tercer paso podemos ejecutar lo siguiente:

El comando es igual que el anterior de las librerías estáticas con la

excepción del -Bdynamic. Es bastante habitual generar los dos tipos de

librería simultáneamente, con lo que es bastante normal encontrar de una

misma librería su versión estática y su versión dinámica. Al compilar sin

opción -Bdynamic pueden tenerse los siguientes casos:

i. Existen liblibreria.a y liblibreria.so. Se toma por defecto liblibreria.a

ii. Sólo existe una de ellas. Se coge la que existe.

iii. No existe ninguna de ellas. Error.

La opción -Bdynamic cambia el primer caso, haciendo que se tome

liblibreria.so en vez de liblibreria.a. La opción -Bdynamic afecta a todas las

librerías que van detrán en la línea de compilación. Para volver a cambiar,

podemos poner -Bstatic en cualquier momento.

Por último hay que decirle al programa, mientras se está ejecutando, dónde

están las librerías dinámicas, puesto que las va a ir a buscar cada vez que se

llame a una función de ellas. Tenemos que definir la variable de entorno

LD_LIBRARY_PATH, en la que ponemos todos los directorios donde

haya librerías dinámicas de interés.

Siendo <path> los directorios en los que están las librerías dinámicas. Se ha

puesto el $LD_LIBRARY_PATH pata mantener su valor anterior y

añadirle los nuevos directorios.

APENDICE B: MACROENSAMBLADOR

TIPOS DE ENSAMBLADORES

Definición: Un ensamblador es un programa que traduce mnemónicos de

un procesador a su correspondiente lenguaje de máquina.

Por la forma en que trabajan existen dos tipos de ensambladores:

Ensambladores de línea. Son aquellos que reciben una sola línea de un

programa y la ensambla independientemente del resto del programa.

Ejemplo: el comando a del servicio debug de MS-DOS.

Ensambladores de archivo. Son aquellos que ensamblan todo un programa

almacenado en un archivo.

Por el tipo de información que manejan los ensambladores se dividen

también en:

Ensambladores propios. (Residentes) Ensamblan programas escritos en

lenguaje del procesador con el que trabaja la máquina. Ejemplo MASM.

Ensambladores cruzados. (Crossassembler) Ensamblan programas escritos en

lenguaje de un procesador diferente al de la computadora de trabajo, pero

no puede ejecutarse.

Macroensambladores. Ensambladores propios o cruzados que permiten

definición y expansión de MACROS.

FACILIDADES DE LOS ENSAMBLADORES DE ARCHIVO.

- Nos permite definir etiquetas (nombre que nos marca una

dirección importante)

- Nos permite reservar memoria con una etiqueta asignada.

- Nos permite ensamblar programas almacenados en archivos.

- Nos permite definir constantes.

- Nos permite dar números en diferentes bases.

- Nos permite evaluar expresiones aritméticas. Ejemplo: mov ax,

30+2

$ LD_LIBRARY_PATH=$LD_LIBRARY_PATH:<path1>:<path2>:<path3>

$ export LD_LIBRARY_PATH

Page 20: Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador

Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador.

Page 19

MASM

Recibe archivos ASCII editados en cualquier editor que contenga programas

en lenguaje ensamblador, tales archivos deben tener extensión .asm y con

una forma específica.

Algoritmo

→ Codificación en ensamblador

→ Editar (archivo.asm)

→ Ensamblar (masm archivo.asm)

→ Código máquina (archivo.obj)

→ Enlazar

→ Crear archivo ejecutable (archivo.exe)

→ Ejecutar.

El archivo objeto no se puede ejecutar porque no tiene la dirección de

memoria donde se ejecutará y será ligado.

PSEUDOINSTRUCCIONES

Definición. Una pseudoinstrucción es una instrucción para el programa

ensamblador, esto es, que solo se ejecuta en el momento de ensamblar,

además no generar código.

Pseudoinstrucciones para definir segmentos:

SEGMENT: Define el inicio de un nuevo segmento. Su formato es:

ENDS: Define el final de un segmento. Su formato es:

Los parámetros del SEGMENT son información para el enlazador:

Alineación: Define la dirección a partir de donde puede colocarse el

segmento:

PARA: La dirección inicial del segmento es un múltiplo de 16 (10h).

PAGE: La dirección inicial del segmento es donde empieza una página

(múltiplo de 100h).

WORD: La dirección inicial del segmento es una dirección par.

BYTE: EL segmento inicia donde sea.

Combinación: Define la forma en que el segmento puede combinarse con

otros segmentos para que se tenga el mismo nombre y clase.

Al omitirla el segmento es privado, es decir, no puede combinarse.

STACK: Segmento para usarse con el stack.

PUBLIC: Este segmento puede unirse con todos los segmentos del mismo y

la misma clase para formar una sola.

COMMON: Todos los segmentos del mismo nombre y clase se colocan a

partir de la misma dirección.

Cuando se tienen dos segmentos con el mismo nombre y clase y son

públicos, al ligar se unen en un solo segmento no importando que estén en

archivos distintos. Cuando se usa la psudoinstrucción COMMON van a

utilizar el mismo espacio de memoria, si son de diferente tamaño en

memoria, se toma el tamaño del mayor bloque.

Clase: Indica el tipo de datos que contiene el segmento, siempre se ponen

entre comillas y pueden definirse propios.

„DATA‟: Datos.

„CODE‟: Código.

„STACK‟: Pila.

nombre ENDS

nombre SEGMENT alineación combinación clase

Page 21: Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador

Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador.

Page 20

Pseudoinstrucciones para reservar memoria y definir constantes:

DB: Sirve para reservar un byte en la memoria con un valor determinado.

Su formato es:

DW: Reserva un dato de dos bytes (una palabra) con un valor inicial. Su

formato es:

DD: Reserva un dato de cuatro bytes (doble palabra) con un valor inicial. Su

formato es:

DQ: Reserva un dato de ocho bytes (cuádruple palabra) con un valor inicial.

Su formato es:

DT: Reserva un dato de diez bytes con un valor inicial. Su formato es:

val1 [, val2,..., valn] representa una expresión formada por números en

cualquiera de las siguientes bases:

XXXXb Binaria

XXXXo Octal

XXXXd Decimal

XXXX Decimal

XXXXh Hexadecimal

También pueden ser etiquetas o expresiones aritméticas que involucren

etiquetas o bien cadenas de caracteres, entre apóstrofes.

EQU: Permite definir constantes. Su formato

es:

ORG: Define un desplazamiento inicial para ensamblar las siguientes líneas.

Su formato es:

Pseudoinstrucciones para definir procedimientos:

PROC: Define el inicio de una subrutina.

ENDP: Define el final de una subrutina.

El tipo de la subrutina puede ser:

NEAR: Cercano.

FAR: Lejano.

Al omitirlo se define por omisión de tipo NEAR.

Un ensamblador de archivo, revisa errores de sintaxis, es decir, revisa que

el programa esté bien escrito, más no que funcione.

Para poner comentarios dentro del programa se inician con un „;‟ y todo lo

que este a la derecha será un comentario sobre el mismo renglón.

La estructura del archivo quedaría:

nombre ENDP

nombre PROC tipo

ORG val

etiq EQU val

[nombre] DT val1 [, val2,..., valn]

[nombre] DQ val1 [, val2,..., valn]

[nombre] DD val1 [, val2,..., valn]

[nombre] DW val1 [, val2,..., valn]

[nombre] DB val1 [, val2,..., valn]

Page 22: Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador

Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador.

Page 21

APENDICE C: CONFIGURACION DE VARIABLES

DE ENTORNO

Antes de comenzar a programar será oportuno asegurarse de tener algunas

variables entorno necesarias para poder ejecutar algunas instrucciones

desde la ventana de comandos sin la necesidad de almacenar el código

dentro de los directorios que contienen los comandos/programas que serán

invocados.

Pasos generales para agregar variables de entorno.

1. Presionar Windows + Pausa para abrir las propiedades del sistema.

2. En la ficha 'Opciones avanzadas' clic en el botón 'Variables de entorno'

(Ilustración 1).

Datos SEGMENT PARA ‘DATA’

; Definición de variables y constantes

Datos ENDS

Pila SEGMENT PARA STACK ‘STACK’

DW 100 DUP (0) ; Indica que se tiene que

; repetir la instrucción n-veces con el

; valor que aparece en los paréntesis

Pila ENDS

Codigo SEGMENT PARA ‘CODE’

ASSUME DS:Datos, CS:Codigo, SS:Pila, ES:NOTHING

; Sirve para indicarle al

; macroensamblador cuales

; segmentos son usados por los registros

subrutina1 PROC

; Código de la rutina uno

subrutina1 ENDP

subrutina-n PROC

; Código de la rutina-n

subrutina-n ENDP

; Programa principal

Main PROC FAR

PUSH DS ; Sirve para cuando se

; termine el programa

XOR AX, AX ; regrese al debug o al

; sistema operativo según sea el

; caso.

PUSH AX

MOV AX, Datos

; Actualiza los registros de segmentos de

;datos y extra

MOV DS, AX

MOV ES, AX

; Código del programa principal.

Main ENDP

Codigo ENDS

END Main ; Le indica al macroensamblador que

el ensamble terminó

Page 23: Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador

Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador.

Page 22

a.

b.

Ilustración 1Ficha Opciones avanzadas de Propiedades del sistema.

a.Widows 2000,/XP b. Windows Vista/7

3. En la nueva ventana (Ilustración 2) haremos clic en el botón 'Nueva' de la

sección 'Variables del sistema'.

a.

b.

Ilustración 2Variables de entorno. a Windows 2000/XP b. Windows Vista/7

Page 24: Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador

Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador.

Page 23

4. En la ventana emergente 'Nueva variable del sistema' (Ilustración 3)

poner el nombre de la variable y la ubicación de la carpeta de la variable.

a.

b.

Ilustración 3 Ventana para agregar Nueva variable de sistema a. Windows 2000/XP b. Windows Vista/7

En el campo „nombre‟ escribimos

En el campo „valor‟ tecleamos la ruta en la que se encuentra instalada

nuestra versión actual de JDK pe.:

Hacemos click en aceptar y ahora haremos lo mismo para el compilador

ASM:

Importante. No olvidar que los valores correspondientes a las rutas

pueden variar dependiendo de cómo hayamos llevado a cabo la instalación

del software mencionado.

Busque la variable „ClassPath‟ y proceda a editar su contenido agregando los

siguientes valores al final del campo „valor‟ (después del último punto y

coma „;‟)

(No olvidar el punto y coma „;‟ al final).

Hay que tener MUCHO CUIDADO DE NO BORRAR EL CONTENIDO

EXISTENTE EN ESTAS VARIABLES ya que esto ocasionará problemas con

otras aplicaciones que hagan uso de ellas.

A continuación edite la variable 'Path' agregándole lo siguiente al valor de la

variable:

Hacemos click en aceptar en esta y todas las ventanas abiertas, es

importante recordar que si ya tenemos una instancia de consola debemos

cerrar y volver a abrir para que estos cambios tengan efecto.

Para asegurarse que se han agregado correctamente las variables de

entorno, ejecutar las siguientes instrucciones:

Para verificar la versión de Java que está siendo usada

Para asegurarse que reconoce el comando correspondiente al compilador

de MASM32.

Dado que el comando no tiene una opción para mostrar solo la versión del

compilador, lo que se desplegará en la pantalla será un error que

previamente mostrará la versión del compilador.

Con la diagonal, como si fuese a agregar parámetros, para evitar que se

desplegue en la pantalla las opciones del linker.

De igual manera, se verá en la pantalla un error que previamente mostrará

la versión del enlazador.

C:\> link

C:\> ml

C:\> javac -version

;%JAVA_HOME%\bin;%MASM32%\bin

%JAVAPATH%\src.zip;%JAVAPATH%\lib\tools.jar;

nombre = MASM32, valor = C:\masm32

C:\Archivos de programa\Java\jdk1.x

JAVAPATH

Page 25: Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador

Manual para la Implementación de Programas que Integren los Lenguajes Java y Ensamblador.

Page 24

En la Imagen 4 se puede apreciar el resultado de las ejecuciones una tras

otra.

Ilustración 4 Comprobación de las variables de entorno.

Si en vez de obtener los resultados esperados como se observan en la

imagen se lanza alguno de los siguientes errores:

Entonces probablemente se ha agregado incorrectamente la variable de

entorno y deberá ser necesario volver sobre los pasos para hallar el error.

BIBLIOGRAFÍA

[1] Invocar programas ASM desde java paso a paso (versión PDF)

Autor: Jorge Ruiz Aquino

[email protected]

[2] Using the Java Native Interface

Author: Christopher Batty

Department of Computer Science, University of Manitoba, Winnipeg,

Manitoba, Canada

[3] Lenguaje ensamblador para microprocesadores Intel 80xx/80x86

Autor: M.C. Eduardo René Rodríguez Ávila.

[4] Java(TM) Native Interface: Programmer's Guide and Specification (Java

Series) by Sheng Liang 1999

[5] Java Native Interface: Programmer's guide and specification,

http://java.sun.com/docs/books/jni/html/jniTOC.html

[6] Wikipedia, Java Lenguaje de Programación, NetBeans, Eclipse, etc.

http://wikipedia.org

[7] Invoking Assembly Language Programs from Java

http://today.java.net/pub/a/today/2006/10/19/invoking-assembly-language-

from-java.html

[8] Pagina de descarga de MASM32 http://www.masm32.com/masmdl.htm

[9] Foro de MASM32 http://www.masmforum.com

[10] Pagina del proyecto MASM32 http://www.movsd.com/

"javac" no se reconoce como un comando interno o externo,

programa o archivo por lotes ejecutable.

"ml" no se reconoce como un comando interno o externo,

programa o archivo por lotes ejecutable.

"link" no se reconoce como un comando interno o externo,

programa o archivo por lotes ejecutable.