Menú

Mostrar Mensajes

Esta sección te permite ver todos los mensajes escritos por este usuario. Ten en cuenta que sólo puedes ver los mensajes escritos en zonas a las que tienes acceso en este momento.

Mostrar Mensajes Menú

Temas - ~

#1
Cuando uno va a varios sitios de Galeon.com, como

http://kerneli386.galeon.com

Sale un anuncio que dice que las páginas se perderán
después del 31 de enero de este año.

¿Cómo se podría hacer una lista de los sitios más importantes de Galeon.com, de favoritos y otros orígenes para hacer un mirror, tal vez entre todos, antes de que supuestamente desaparezca?
#2
[youtube=640,480]GHyXB4yObuY[/youtube]
[youtube=640,480]uhaVP5nFGhE[/youtube]


Extracto de audio automatizado de 18 horas del libro entero (para estudiarlo más fácil mientras hacemos otra cosa u evaluar si contiene trucos que nos pueden servir y podemos entender fácilmente al oírlos):
http://archive.org/download/LibroEnsambladorCharte_2005_2009/ExtractoAudioLibroEnsamblador2005Charte.mp3




http://archive.org/download/LibroEnsambladorCharte_2005_2009/LibroEnsamblador2005CharteOjeda.zip

http://archive.org/download/LibroEnsambladorCharte_2005_2009/Ensamblador_Charte_CD_2005.zip

http://archive.org/download/LibroEnsambladorCharte_2005_2009/ExtractoTextoLibroEnsamblador2005CharteOjeda.zip



CitarEl libro de Ensamblador de Francisco Charte Ojeda, en su versión 2005 o 2009, es un importantísimo libro que enseña a programar en Ensamblador x86 para las PCs de 16 y 32 bits.

Es tal vez el mejor y más claro libro sobre Ensamblador en Español.

Sin embargo, lastimosamente ya no se encuentra a la venta desde hace varios años, por lo que los nuevos programadores de habla española/latinoamericana no podrían disfrutar del beneficio de aprender Ensamblador. Yo traté de comprarlo allá por el 2011 en Amazon pero jamás me lo enviaron ya que para comenzar también se había acabado en bodega. Se podía comprar y lo enviarían cuando lo encontraran, pero jamás me lo enviaron, y pagué unos 49 dólares por él en Amazon, aunque no sé si me los cobraron o no. Lo más probable es que no, pero ya no está disponible para comprarse.

Si bien solo habla de los modos de 16 y 32 bits, nos servirá de excelente base, si también lo complementamos junto con los diferentes manuales de Intel y de algoritmos, formatos de archivo y llamadas de sistema para cada sistema operativo.

Todos estos factores hacen que sea más difícil aprender a programar en Ensamblador para quienes hablamos Español, a menos que contemos con este libro, realmente el mejor sobre el tema que por lo menos yo he podido ver, escrito en Español, y de una manera que realmente simplifica los conceptos básicos de la programación en ese lenguaje, como si de una clase se tratara.
#3
[youtube=640,480]gdUipEt4WPk[/youtube]

Link de descarga del manual (384 páginas, 100 Megabytes de JPG):
http://archive.org/download/Phoenix_PC_BIOS_Books/1_System%20BIOS%20PC%20and%20EISA%202ndEd.zip

Con este libro aprenderemos a programar el BIOS base de todas las PC estándar. Necesitamos saber llamar a las funciones del BIOS con ensamblador de NASM, TASM o MASM, con Turbo C++ o con inline assembly de los diferentes compiladores. Es una adición importante a referencias como la de Ralf Brown ya que muestra cada campo y servicio del BIOS base de forma limpia, proveniente de un fabricante principal de BIOS (Phoenix).

Este video contiene la vista previa del video y el audio del texto completo (fue procesado a computadora con OCR de Lucion File Converter y leído a MP3 con Balabolka así que se oye exactamente lo que la computadora interpretó).

El video está pensado para poder oír cada detalle que el libro contiene y así decidir si hay información especial de interés, haciendo un esfuerzo mínimo para leerlo.
#4
[youtube=640,480]Xpcg9wJWU1w[/youtube]

La explicación del funcionamiento de la función XOR a nivel de compuertas lógicas es bastante simple.

En principio, tenemos como mínimo una entrada de 2 bits distintos.

El circuito XOR nos devolverá un 1 como resultado siempre y cuando ambos bits sean diferentes.

En la entrada, necesitamos usar una compuerta OR de 2 entradas.

También necesitamos una compuerta AND de 2 entradas en la entrada, y frente a esta una compuerta de negación para invertir el resultado de dicha compuerta AND.

La primera pata de entrada de la compuerta OR va a la primera pata de entrada de la compuerta AND invertida, y la segunda pata de la compuerta OR de entrada va a la segunda pata de la compuerta AND invertida de entrada.

En otras palabras, queremos obtener el resultado del OR y del AND invertido para los dos bits iniciales de entrada.

Los dos bits de resultado obtenidos por la compuerta OR y AND invertida los haremos pasar por una compuerta AND final de dos entradas.

El resultado de esta última AND será el valor XOR.


La intención de este circuito es usar el OR para detectar la presencia de un 1 y devolver un 1 como resultado; y la intención de la AND invertida es detectar la presencia de un 0 y devolver un 1 como resultado.

Las compuertas OR están orientadas a devolver un 1 cuando hay por lo menos un 1 de entrada.

Las compuertas AND están orientadas a devolver un 0 cuando hay por lo menos un 0 de entrada. Con la compuerta de negación obtenemos un 1 de la AND cuando hay un 0 presente.


Así que con el OR detectamos si hay un 1 presente, y devolvemos 1.
Con el AND detectamos si hay un 0 presente, y en ese caso obtenemos un 0 que invertimos para obtener un 1 en la presencia de un 0 de entrada.

Ahora, si hay un 1 presente, el OR nos devolverá 1.
Y si hay un 0 presente, el AND invertido nos devolverá 1.


Tomemos como ejemplo 11 binario.
Cuando la compuerta OR lo procese, obtendremos 1, que significa que hay un 1 presente en la entrada.
Ahora, cuando la compuerta AND procese los dos bits de entrada originales a 1, también devolverá un 1, pero la compuerta de negación invertirá ese resultado de 1 a 0 para indicar que no había ningún 0 presente en la entrada.
Cuando el 1 del OR y el 0 del AND invertido ingresen a la compuerta AND final, obtendremos un 0 en respuesta de la entrada original 11 binario. Esto indicará que ambos bits tenían el mismo valor.

Es como si el circuito XOR fuera una pregunta.: ¿Son ambos bits de entrada diferentes? La respuesta será un 1 para indicar VERDADERO si realmente son diferentes.
Ahora podemos ver claramente que si ambos bits de entrada son iguales como en este caso con 11 binario, el resultado devuelto por la función XOR será 0.



Tomemos otro ejemplo, con 10 binario.
La compuerta OR toma ambos bits, 1 y 0, y devuelve 1 ya que hay por lo menos un 1 presente.
La compuerta AND toma ambos bits 1 y 0, y devuelve 0 ya que hay por lo menos un 0 presente.
Pero con la compuerta de negación que le sigue a esta AND obtenemos un 1, lo que indica que hay un 0 presente.

Ahora, el bit con valor 1 de resultado de la OR, y el bit con valor 1 de la AND invertida entran en la última AND, la AND de salida, y ya que ambos bits son 1, devolvemos 1.
Lo que indica esto es que la OR tomó el 1 y el 0 y detectó la presencia de un 1, devolviendo 1.
También indica que la AND invertida tomó el 1 y el 0 y detectó la presencia de un 0, devolviendo 1.
Ya que el circuito OR y AND invertido nos indican por su lado que hay tanto un 1 como un 0 presentes, devolvemos un 1 para la función XOR del circuito completo, para indicar que ambos bits eran diferentes.

Como vemos también, al nivel más fundamental siempre operamos las compuertas de 2 en 2, así que resolver será fácil. Incluso en la aritmética decimal normal operamos de 2 en 2 al nivel lógico más simple.

El siguiente código de javascript demuestra cómo se vería implementada como programa la función lógica del circuito XOR. Siempre que los 2 bits de entrada sean iguales, el programa devolverá 0. Si son diferentes, este devolverá 1.

Paso 1.: Necesitamos 2 variables de entrada de por lo menos 1 bit de tamaño.
Paso 2.: Aplicamos OR entre ambas variables de entrada.
Paso 3.: Aplicamos AND entre ambas variables, y negamos los valores de bits del resultado.
Paso 4.: Aplicamos AND al resultado del OR y del NAND. Este es el valor XOR.


La mayoría de lenguajes de programación y ensambladores tienen operadores o instrucciones XOR. Estas son especialmente útiles para generar código más breve que asigne 0 a una variable o registro al aplicarle XOR con su mismo valor. Como hemos visto, ya que todos los bits serán los mismos al usar el mismo registro del procesador o variable de memoria como primer y segundo operando para la XOR, todos los bits quedarán a cero para indicar que todos eran iguales.



javascript:

/* Paso 1: Necesitamos 2 variables de entrada de por lo menos 1 bit de tamaño. */
var bits_A = 1;
var bits_B = 1;

var OR_0        = bits_A|bits_B;     /* Paso 2: Aplicamos OR entre ambas variables de entrada. */
var NAND_0      = ~(bits_A&bits_B);  /* Paso 3: Aplicamos AND entre ambas variables, y negamos los valores de bits del resultado. */
var XOR_AND_OUT = OR_0&NAND_0;       /* Paso 4: Aplicamos AND al resultado del OR y del NAND. Este es el valor XOR. */

alert(XOR_AND_OUT);

void(0);

#5
http://archive.org/download/CursoAdmisionITCA/2016.html
http://archive.org/download/CursoAdmisionITCA/2016.html
http://archive.org/download/CursoAdmisionITCA/2016.html
http://archive.org/download/CursoAdmisionITCA/2016.html


Saludos.

Aquí mando un curso de admisión que acabo de estudiar para tratar de entrar a una carrera técnica y aprender de cómo implementar dispositivos de hardware para PC.

Es un repaso básico de Física, Matemática y Técnicas de Estudio, pero podría servir para volver a encender esos recuerdos y que ya no cuesten tanto.

También pienso poner el 100% de esa carrera en línea gratis en caso de que realmente logre estudiarla, así que voy a estar mandándote las clases de esa carrera para que también te quede una copia entera de esa carrera, en videos de YouTube, escaneos en el Archive.org y otros posibles sitios de recursos.

Me gustaría ver el contenido de otras carrera. Todos nos beneficiaríamos, Poner carreras enteras gratis parece no ser tan difícil pero parece ser algo nunca antes visto en internet, así que atraería mucha atención y ganancias.


Una cosa que vale la pena mencionar es que en Física siempre empezamos por estudiar las unidades de medida y la conversión de unidades.

También cabe mencionar que para quien sea programador, estudiar ayudándose como mínimo de programas en javascript e interfaces HTML para calcular y hacer herramientas para automatizar y usar las diferentes fórmulas y conceptos, es una gran ventaja.
#6
Semana 1 - Calculando el Calendario Mentalmente.
Aprendiendo la Secuencia de los Días 1-31.

[youtube=640,480]JtBEHSX8nnE[/youtube]


Este es un curso corto sobre un algoritmo para calcular el calendario usando solo cálculos mentales de aritmética simple.

Actualmente solo hay un video para la Semana 1, pero eso debería dar suficiente tiempo para entender cada parte del curso de una forma realmente detallada.

El algoritmo es muy liviano así que es adecuado para permitir su uso y cálculos mentales con este, así que también debería ser extremadamente simple, optimizado y ligero si se usa para implementar una aplicación de administración de fecha, por ejemplo en un BIOS de código abierto o en un kernel.

No se trata de calcular un timestamp sino que de los números en cuestión 1-31 y sus nombres de día de semana correspondientes.
CitarCalculando el Calendario Mentalmente.
Aprendiendo la Secuencia de Días del 1 al 31.



La primera cosa que necesitamos aprender para calcular el calendario mentalmente, es aprender la secuencia de los días en orden vertical. Esto nos permitirá alcanzar todas las semanas rápidamente para cualquier día, también nos permitirá obtener todos los números de días para cada día de la semana.

La única otra cosa que nunca debemos olvidar es el nombre de día de semana en el que comienza el mes, y también el número de días de ese mes. Simplemente debemos memorizar eso, y normalmente es suficiente memorizar eso para el mes actual. A medida pase el tiempo, nos resultará más rutinario recordar esos detalles.

Tenemos meses con 28, 29, 30 y 31 días, pero si aprendemos la secuencia de 31 días podremos calcular cualquier día de meses más cortos.

La siguiente es la secuencia verbal que necesitamos aprender. Una única línea es la secuencia para un único día de semana. El mes puede iniciar en cualquier día, así que la secuencia para el día 1 o el resto de días puede caer en cualquier día de semana:

1, 8,  15, 22, 29.
2, 9,  16, 23, 30.
3, 10, 17, 24, 31.
4, 11, 18, 25.
5, 12, 19, 26.
6, 13, 20, 27.
7, 14, 21, 28.

Simplemente memoriza los números anteriores y mira si puedes luego inspeccionar el calendario para el mes actual y hacer concordar esta secuencia con la secuencia para el mes en cuestión en que estás interesado. Solo hay 7 días de la semana, así que esta lista solo puede empezar en 7 formas diferentes, pero esta misma secuencia se usa siempre para las 7 combinaciones.

Ahora mira si puedes determinar el primer día de semana sin ver el calendario, y también el último día. Practica con otros días a medida que los necesites.


Determinando el Último Día.

Tenemos meses con 28, 29, 30 y 31 días.
Los meses de 28 días terminan el día de semana antes del que empezaron.
Los meses de 29 días terminan el día de semana en el que empezaron.
Los meses de 30 días terminan el siguiente día de semana del que empezaron.
Los meses de 31 días terminan dos días de semana después del que empezaron.

El primer día del siguiente mes es simplemente el siguiente día de semana para cualquiera de los últimos días de semana que acabamos de describir.

Ahora mira si puedes calcular el último día de semana para este mes y luego el primer día de semana para el siguiente mes al avanzar al siguiente día de semana.

Ahora también trata de calcular el día de semana de varios cumpleaños o días de semana de fechas en las que necesites terminar o pagar algo. También trata de calcular los días de semana para el Sábado o Domingo siguientes.

#7
Programar el puerto paralelo en Windows

Descargar lpthandler.tar

Solo necesitamos conectar un LED entre el pin 9 y el 22 del paralelo.

O como muestra el esquema, entre cualquiera de los pines anaranjados (los pines de datos) y cualquiera de los pines grises (pines de polo a Tierra, GND). Tenemos un total de 16 de esos pines, 2 pines por bit de datos para poder conectar las 2 patas de un LED u otro dispositivo.

Asegurarse de poner el LED en la polaridad correcta, o darle vuelta, o simplemente no va a dejar pasar la electricidad y no va a encender.


Uso de este programa para encender todos los 8 LEDS:
lpthandler.exe 3bc 11111111

  o sino el puerto 378
lpthandler.exe 378 11111111

  o sino el puerto 278
lpthandler.exe 278 11111111


Uso de este programa para apagar todos los 8 LEDS:
lpthandler.exe 3bc 00000000

  o sino el puerto 378
lpthandler.exe 378 00000000

  o sino el puerto 278
lpthandler.exe 278 00000000


Cada uno de los 8 bits a escribir debe ser un 1 o 0.
Un 0 apaga y un 1 enciende.



/*
En resumen solo necesitamos:

 Out32(Direccion_Base_Puerto_Paralelo+2, 0);          //Resetear Puerto de Control
 Out32(Direccion_Base_Puerto_Paralelo,   0xFF-0x00);  //Escribir el Puerto de Datos
*/



//Aquí, la Direccion_Base_Puerto_Paralelo
//puede ser:
//          0x3BC -- LPT1
//          0x378 -- LPT1
//          0x278 -- LPT2
///

//Necesitamos resetear el Puerto de Control escribiéndole un 0
//para configurar sus opciones, controladas por cada uno de
//sus bits:
///
 Out32(Direccion_Base_Puerto_Paralelo+2, 0);

//Enviamos un valor entre 0 y 255 al puerto de Datos:
///
 Out32(Direccion_Base_Puerto_Paralelo,   0xFF-0x00);


Por si no se entiende el código, se puede ver cómo se escribió en tiempo real, carácter por carácter como en la programación original:

>> Ver Tutorial Animado de Código de lpthandler.c <<





Cita de: ~ en  7 Abril 2016, 17:35 PMLo primero son los binarios y el código fuente del driver de acceso general a bajo nivel:

inpout32_source_and_bins.zip [Mirror 1]

inpout32_source_and_bins.zip [Mirror 2]


Después necesitamos saber qué direcciones de I/O tiene el puerto paralelo. Los puertos de I/O son como direcciones de memoria que van desde 0 hasta 65535. Cada una de esas posiciones podemos enviar 1, 2 o 4 bytes, o nosotros podemos recibir 1, 2 o 4 bytes. Por ahora solo vamos a enviar 1 byte a la vez.



El LPT1 está en el puerto (0x378, 378h)(888 decimal) o (0x3BC, 3BCh)(956 decimal).

El LPT2 está en el puerto (0x278, 278h)(632 decimal).

El LPT3 está en el puerto (0x3BC, 3BCh)(956 decimal).

El puerto paralelo es un periférico de 8 bits, así que usa 8 pines de datos para representar los 8 bits de cada byte (ya que usa datos y señales en paralelo, simultáneos), y esos son los pines que manipulamos con encendido o apagado cada vez que escribimos, por ejemplo, al puerto 0x378 (Los Pines Anaranjados, del 2 al 9):





Conector Hembra, en la Tarjeta Madre:





Ahora necesitamos usar void _stdcall Out32(short PortAddress, short data), que viene del driver inpout32.dll y hwinterface.sys.

Algo como esto:
Out32(378h, 255-0);





El código completo es el siguiente:
//NOTE: Compile with GCC under MinGW.
//
// gcc lpthandler.c -o lpthandler.exe
//
//Usage:
// lpthandler.exe LPT_Port Byte_Bit_Data
//
// LPT_Port:
//  - can be 3bc, 378 or 278
//
// Byte_Bit_Data:
//  - can range from 00000000 to 11111111 (written like that, in binary).
//    Every bit controls one of 8 LEDs.
//
// LEDs are connected between DATA and GROUND lines.
// DATA to GROUND lines are connected like this, for pins:
//
// DATA is + and GROUND is -
//
//  2-18
//  3-19
//  4-20
//  5-21
//  6-22
//  7-23
//  8-24
//  9-25
//
// Remember to set the parallel ports as Standard/Normal in the BIOS
// to ensure proper working of the basics with this program.
///

#include <stdio.h>
#include <windows.h>

typedef short _stdcall (*_Out32)(short portaddr, short value);
typedef short _stdcall (*_Inp32)(short portaddr);

int main(int argc, char *argv[])
{
HINSTANCE INPOUT32_DLL_Handle;
_Inp32 Inp32;
_Out32 Out32;


//Load the inpout32.dll library. It's also associated
//with hwinterface.sys, but it should open it by itself:
///
 INPOUT32_DLL_Handle=LoadLibrary("inpout32.dll");
 if(INPOUT32_DLL_Handle == NULL)
 {
  printf("LoadLibrary failed for inpout32.dll...\n\n");
  return -1;
 }


//Get access to the Out32/Inp32 functions from inpout32.dll:
///
 Out32 = (_Out32)GetProcAddress(INPOUT32_DLL_Handle, "Out32");
 Inp32 = (_Inp32)GetProcAddress(INPOUT32_DLL_Handle, "Inp32");

//NOTE: The following two lines are the actual logic of the program
//      and are at the top of importance and the program's key logic.
//      Everything else could be considered API noise:

//Configure the CONTROL Port with a 0 to sanitize the port state:
///
 Out32(strtol(argv[1],NULL,16)+2, 0);  //Bit 0: Strobe
                                       //Bit 1: Auto Line Feed
                                       //Bit 2: Initialize Printer
                                       //Bit 3: Select Printer
                                       //Bit 4: Enable IRQ Via Ack Line
                                       //Bit 5: Enable Bi-Directional Port
                                       //Bit 6: Unused
                                       //Bit 7: Unused



//Write the Data port with the desired 8-bit value:
///
 Out32(strtol(argv[1],NULL,16), strtol(argv[2],NULL,2));


//Unload our inpout32.dll library:
///
 FreeLibrary(INPOUT32_DLL_Handle);

return 0;
}

#8
filesopen Espera_aleatoria_minima Espera_aleatoria_maxima Nombre_base_de_datos Numero_de_fila_de_configuracion

Aquí tengo un programa de consola que escribí, que abre automáticamente y al azar archivos locales o URLs tomadas de una base de datos SQLite3 la cual maneja por sí misma usando la librería de Amalgamación de SQLite3.

Está completamente escrita en C y funciona bajo Windows (aunque tal vez pueda funcionar bajo Wine).

Aquí está el binario compilado:
FILESOPEN.EXE

Aquí se puede ver y aprender a escribir un programa en C básico para manejar una base de datos SQLite3:
>> Grabación de Texto para el Visor Aleatorio de Archivos y URLs <<

La estructura documentada y el uso de la base de datos está contenido en dicha grabación de la escritura del código.

Se puede hacer una prueba del funcionamiento con la siguiente base de datos que contiene más de 2 millones de nombres de dominio provenientes de la lista diaria de 1 millón de sitios más importantes de Alexa:
domains_alexaranks.db

Para correr el programa, solo se necesita el siguiente comando:

filesopen 1 1 domains_alexaranks.db 1




Aquí está el código principal (compilado bajo MinGW):
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "SQLite3-Amalgamation-3.12.0/sqlite3.h"
#include "SQLite3-Amalgamation-3.12.0/sqlite3.c"
#include "SQLite3-Amalgamation-3.12.0/sqlite3ext.h"
#include <windows.h>

const char sqlite3_version[] = SQLITE_VERSION;

//Set default values for the number of table rows and for the current column
//this last one will be selected at random:
///
int SQLite3_Row_Ctr=1;
int SQLite3_Current_Row=1;

sqlite3      *SQLite3_DB_Obj;
sqlite3_stmt *SQLite3_State;
int           SQLite3_DB_Res_Handle;
char         *SQL_String;
char         *SQLite3_ErrorMsg=NULL;
char         *SQLite3_zTail_String;



//These are the default minimum and maximum number of minutes to wait
//before trying to open other file/directory entry:
///
int minwait=1;
int maxwait=1;


long minmax_rand(long min, long max)
{
return rand()%((max+1) - min) + min;
}


char *config_tablename;
char *config_datarowname;
char *config_idrowname;
char *config_fileprotocol;

static int SQLite3_Callback_config(void *NotUsed, int argc, char **argv, char **azColName)
{
config_tablename=malloc(512);
config_datarowname=malloc(512);
config_idrowname=malloc(512);
config_fileprotocol=malloc(512);

sprintf(config_tablename,"%s",argv[0]);
sprintf(config_datarowname,"%s",argv[1]);
sprintf(config_idrowname,"%s",argv[2]);
sprintf(config_fileprotocol,"%s",argv[3]);


printf("Getting database configuration...\n");
printf("tablename=%s\ndatarowname=%s\nidrowname=%s\nfileprotocol=%s\n\n", config_tablename, config_datarowname, config_idrowname, config_fileprotocol);


return 0;
}


static int SQLite3_Callback(void *NotUsed, int argc, char **argv, char **azColName)
{
int x=0;
int requiredSize=0;
int   openstrlen=0; char *cmd=NULL;
char *cmd2=NULL;
char *openstr="open";
char *openstrW;
char *explorerstr="C:\\WINDOWS\\explorer.exe";
char *explorerstrW;

int   execres=0;

openstrW=malloc(131072);
explorerstrW=malloc(131072);
cmd=malloc(131072);
cmd2=malloc(131072);

MultiByteToWideChar(
                     (UINT)CP_UTF8,
                     (DWORD)0,
                     (LPCSTR)explorerstr,
                     (int)-1,
                     (LPWSTR)explorerstrW,
                     (int)131072
                    );

MultiByteToWideChar(
                     (UINT)CP_UTF8,
                     (DWORD)0,
                     (LPCSTR)openstr,
                     (int)-1,
                     (LPWSTR)openstrW,
                     (int)131072
                    );




for(x=0; x<argc; x++)
{
  snprintf(cmd,131072,"\"%s%s\"",config_fileprotocol,argv[x]);

/*
int MultiByteToWideChar(
  _In_      UINT   CodePage,
  _In_      DWORD  dwFlags,
  _In_      LPCSTR lpMultiByteStr,
  _In_      int    cbMultiByte,
  _Out_opt_ LPWSTR lpWideCharStr,
  _In_      int    cchWideChar
);
*/
  MultiByteToWideChar(
                      (UINT)CP_UTF8,
                      (DWORD)0,
                      (LPCSTR)cmd,
                      (int)-1,
                      (LPWSTR)cmd2,
                      (int)131072
                     );

  printf("%ld: %s\n\n", SQLite3_Current_Row, cmd);

/*
HINSTANCE ShellExecute(
  _In_opt_ HWND    hwnd,
  _In_opt_ LPCTSTR lpOperation,
  _In_     LPCTSTR lpFile,
  _In_opt_ LPCTSTR lpParameters,
  _In_opt_ LPCTSTR lpDirectory,
  _In_     INT     nShowCmd
);

*/

  execres=(int)ShellExecuteW(
                (HWND)0,
                (LPCWSTR)openstrW,
                (LPCWSTR)explorerstrW,
                (LPCWSTR)cmd2,
                (LPCWSTR)NULL,
                (INT)SW_SHOWNORMAL
               );


  switch(execres)
  {
   case 0:
   printf("exec: 0");
   break;

   case ERROR_BAD_FORMAT:
    printf("exec: ERROR_BAD_FORMAT");
   break;

   case SE_ERR_ACCESSDENIED:
    printf("exec: SE_ERR_ACCESSDENIED");
   break;

   case SE_ERR_ASSOCINCOMPLETE:
    printf("exec: SE_ERR_ASSOCINCOMPLETE");
   break;

   case SE_ERR_DDEBUSY:
    printf("exec: SE_ERR_DDEBUSY");
   break;

   case SE_ERR_DDEFAIL:
    printf("exec: SE_ERR_DDEFAIL");
   break;

   case SE_ERR_DDETIMEOUT:
    printf("exec: SE_ERR_DDETIMEOUT");
   break;

   case SE_ERR_DLLNOTFOUND:
    printf("exec: SE_ERR_DLLNOTFOUND");
   break;

   case SE_ERR_FNF:
    printf("exec: SE_ERR_FNF");
   break;

   case SE_ERR_NOASSOC:
    printf("exec: SE_ERR_NOASSOC");
   break;

   case SE_ERR_OOM:
    printf("exec: SE_ERR_OOM");
   break;

   case SE_ERR_SHARE:
    printf("exec: SE_ERR_SHARE");
   break;
  }


  sleep(60*(int)minmax_rand(minwait,maxwait));
}

free(cmd);
free(cmd2);
free(openstrW);
free(explorerstrW);


return 0;
}


static int SQLite3_Callback2(void *NotUsed, int argc, char **argv, char **azColName)
{
SQLite3_Row_Ctr=atol(argv[0]);
return SQLite3_Row_Ctr;
}



void clear_state()
{
//NOTE: This is for the good practice of not leaving
//      freeing of resources or other default operations
//      at their default state but accelerate and ensure
//      the global sanity of the environment and the program
//      by specifying every operation exactly as we want it:
///
sqlite3_finalize(SQLite3_State);
sqlite3_close(SQLite3_DB_Obj);
free(SQL_String);

}






int main(int argc, char *argv[])
{
atexit(clear_state);
SQL_String=malloc(4096);



if(argc>=5)
{
  if(!(minwait=atoi(argv[1])))minwait=1;
  if(!(maxwait=atoi(argv[2])))maxwait=1;
}
  else
  {
   printf("Usage: filesopen min_minutes max_minutes SQLITE3_Database_Path Database_Config_ID\n\n");
   return -2;
  }


//Open the database and see if it was successful. If not, just exit the program:
///
  SQLite3_DB_Res_Handle=sqlite3_open(argv[3], &SQLite3_DB_Obj);

  if(SQLite3_DB_Res_Handle!=SQLITE_OK)
  {
   printf("Error opening database\n\n");
   return -1;
  }


  //Get the configuration of the database to use the proper table and field names,
  //as well as basic formatting for the data:
  ///
   snprintf(SQL_String, 4096, "SELECT tablename,datarowname,idrowname,fileprotocol FROM config WHERE configid=%s LIMIT 1", argv[4]);
   SQLite3_DB_Res_Handle=sqlite3_exec(
                                      SQLite3_DB_Obj,
                                      SQL_String,
                                      SQLite3_Callback_config,
                                      SQLite3_zTail_String,
                                      &SQLite3_ErrorMsg
                                     );







//Get all columns for the first time to count them.
//Its callback will return the count in SQLite3_Row_Ctr:
///
  snprintf(SQL_String, 4096, "SELECT COALESCE(MAX(%s)+1, 0) FROM %s", config_idrowname, config_tablename);
  SQLite3_DB_Res_Handle=sqlite3_exec(
                                     SQLite3_DB_Obj,
                                     SQL_String,
                                     SQLite3_Callback2,
                                     SQLite3_zTail_String,
                                     &SQLite3_ErrorMsg
                                    );

printf("Cycling through %ld files...\n", SQLite3_Row_Ctr);


while(1)
{
  //Go to next row (selected randomly):
  ///
   SQLite3_Current_Row=minmax_rand(1, SQLite3_Row_Ctr);


  //Get random files to open:
  ///
   snprintf(SQL_String, 4096, "SELECT %s FROM %s WHERE %s=%ld LIMIT 1", config_datarowname, config_tablename, config_idrowname, SQLite3_Current_Row);
   SQLite3_DB_Res_Handle=sqlite3_exec(
                                      SQLite3_DB_Obj,
                                      SQL_String,
                                      SQLite3_Callback,
                                      SQLite3_zTail_String,
                                      &SQLite3_ErrorMsg
                                     );


  //If there was a database error or fault, just end:
  ///
   if(SQLite3_ErrorMsg)return 0;
}


return 0;
}


#9
Este es el libro "El Habla de Mi Tierra", que trata sobre el estudio del idioma Español en gran detalle y en todos sus aspectos.

Contiene 459 imágenes con resolución de 1,700px × 2,338px.

Citar El Habla de Mi Tierra.zip (401 MB)
MD5:345334d526b20da63c4607b231998673




En caso de que el link haya expirado, esta es la URL en la que mantengo actualizado y vigente los links de descarga en un momento dado:

Descargar El Habla de Mi Tierra; Rodolfo María Ragucci (Actualizado el 14 de Noviembre del 2014)







Dado lo raro que es encontrar ahora literatura de esta calidad y que necesitaba preservar mi ejemplar ya desgastado por el uso y por el tiempo (incluso antes de tenerlo yo, allá por los años 70/80).

Originalmente lo publiqué como imágenes JPG sueltas para poder ser vistas fácilmente sin descargar todo el paquete y sin consumir demasiados recursos del cliente y del servidor, y ahora he subido el ZIP con todas las imágenes en link anterior.
#10
Hace un par de meses comencé a descargar el torrent de Geocities (de 641 Gigabytes), a una velocidad máxima de 400 Kilobytes por segundo, después de varios intentos parciales anteriores por buscar sitios antiguos de Internet de los 90's y principios del 2000, especialmente sitios técnicos con información interesante, como los sitios de Geocities en SiliconValley.

Necesité 3 Terabytes (1 disco de 1 Terabyte para descargar el torrent y otro disco de 2 Terabytes para descomprimir y finalmente guardar los contenidos, con un tamaño de clúster de 512 bytes y compresión NTFS activada, para ahorrar el máximo espacio posible), y usando también una laptop Dual Core a 2.4 GHz y 2 GB de memoria. Este es realmente un ejercicio muy interesante para aprender a manipular, copiar, detectar errores de CR5/MD5/SHA, administrar una enorme cantidad de datos arbitrarios del mundo real, y cosas que realmente no son tan críticas como la necesidad de reducir el tamaño del archivo MFT en una partición NTFS (con algo como Clean Disk Security), entre otras cosas a descubrir con más tiempo de tener que manejar tantos datos.



Este es el link del torrent:
Código (magnet) [Seleccionar]
magnet:?xt=urn:btih:2DC18F47AFEE0307E138DAB3015EE7E5154766F6&dn=geocities.archiveteam.torrent&tr=udp%3a%2f%2ftracker.openbittorrent.com%3a80&tr=udp%3a%2f%2ftracker.publicbt.com%3a80&tr=udp%3a%2f%2ftracker.istole.it%3a80%2fannounce&tr=udp%3a%2f%2fopen.demonii.com%3a1337


Este es el link que he puesto para visualizar cómodamente el contenido:
http://geocities.archefire.org/

Y el historial de intentos y del procedimiento para ponerlo finalmente en disco:

Agregado el dominio geocities.archefire.org (¿Qué Tiene De Nuevo para Ofrecer?)

Descargando el Torrent de Geocities


Resulta que hay mucho contenido que se ve mal si se trata de acceder localmente porque usa muchas URLs absolutas, y otros casos en los que el contenido puede existir pero estar disperso entre los diferentes directorios del torrent, y son tan enormes que lo mejor es buscar y redirigir automáticamente con PHP.

Así que puse todo el contenido, archivo por archivo, con el extra de que se puede ver el contenido de cada directorio existente sin que index.html estorbe, que es algo que no es posible hacer con otros mirrors como Reocities u OOcities, y en consecuencia no es posible saber de la existencia de mucho contenido ocultado por index.html, pero que está superado en este mirror que creé para mi conveniencia de visualización, y también para alguien más que quisiera poder ver el respaldo de Geocities en su totalidad, con absolutamente todo lo que eso implica.

Es posible que  este mirror esté ocasionalmente offline porque está en un disco USB de 3.5", y si necesito reconfigurar algo (o ahorrar electricidad, o por otras razones), sería mejor usar un disco interno o uno externo pero de 2.5".
#11
Hace un tiempo, cerca de hace 6 meses, en el 2012, aproximadamente de Junio a Agosto, estuve trabajando en un emulador de VGA y CPU x86 como manera tanto de entender HTML5 como de llevar mi conocimiento a un lugar más accesible, tal como es el navegador.

Versión Pre-Alpha "Final"

Historial de Versiones Pre-Alpha:
Versión 0.1
Versión 0.2
Versión 0.3
Versión 0.4
Versión 0.5





El código de emulador de CPU x86 que estoy intentando rediseñar para una emulación realmente adecuada, escalable y con código mantenible (por ahora en javascript y HTML5) es este (que recupera un código de boot x86 de floppy, pero obviamente todavía no hay BIOS ni soporte para las instrucciones del CPU globalmente):

Emulador de CPU con visor VGA provisional (2013-03-02).





Durante el repaso del código antiguo me he dado cuenta de varios requerimientos que debería satisfacer.

El requerimiento más importante a superar en este momento es cómo manejar grupos de instrucciones, ya que muchísimas de estas difieren solo en sus opcodes y en la operación que efectúan, pero se rigen por la misma tabla de decisiones. Por ahora, uso como ejemplo la versión de opcode 0x31 de la instrucción xor.

Hay muchas más que igual que esta, usan la misma tabla de operadores en 16 bits (y más adelante, otra para 32 bits, y otra mucho más adelante, para 64 bits).



El código básico para manejar las ramificaciones de esta tabla de la forma más básica es la siguiente (en javascript):

function mod(modrm){
var mod=parseInt("11000000b", 2);
var mod_val=(modrm&mod)>>6;
return mod_val;
}



function reg(modrm){
var reg=parseInt("00111000", 2);
var reg_val=(modrm&mod)>>3;
return reg_val;
}


function rm(modrm){
var rm=parseInt("00000111", 2);
var rm_val=(modrm&rm);
return rm_val;
}



function scale(sib){
var scale = parseInt("11000000b", 2);
var scale_val=(sib&scale)>>6;
return scale_val;
}


function index(sib){
var index = parseInt("00111000b", 2);
var index_val=(sib&index)>>3;
return index_val;
}


function base(sib){
var base  = parseInt("00000111b", 2);
var base_val=sib&base;
return base_val;
}



function xor_16()
{
    var ctr=0x00;

    var str="";
    for(var modrm=0; modrm<256; modrm++)
    {
     str+="db 0x31,"+modrm;

     if(mod(modrm)==0)
     {
      if(rm(modrm)==6)
       str+=",0,0\n";
      else
      {
       str+="\n";
       continue;
      }
     }
      else if(mod(modrm)==1)
      {
       str+=",0\n";
       continue;
      }
       else if(mod(modrm)==2)
       {
        str+=",0,0\n";
        continue;
       }
        else if(mod(modrm)==3)
        {
         str+="\n";
         continue;
        }
    }

return str;
}



Como vemos, lo más importante aquí es el campo Mod del byte Mod/RM, que puede tener un valor de 0 a 3, y dependiendo de este, se usan diferentes desplazamientos de memoria o registros.

Una vez que tenemos este código, lo difícil es decidir cómo reutilizar este código eficientemente para absolutamente todas las demás instrucciones que esperan dicho byte Mod/RM, usando punteros a funciones, y probablemente funciones simples crudas para todas las operaciones básicas (AND, OR, XOR, NOT, NEG, suma, resta, muliplicación, división, desplazamientos de bits, rotaciones de bits, etc.).





Otro aspecto importante es crear un cuerpo de rutinas para recuperar adecuadamente las instrucciones. Para esto en primer lugar necesitamos una tabla con los tamaños esperados de todas las instrucciones existentes. Esto también puede ayudarnos para aislar instrucciones que actualmente no podemos manejar y para que podamos saltarlas y/o recuperarlas por separado.

Esto se complica porque una instrucción puede estar precedida por un número variable de bytes de prefijo, y estos también deben considerarse parte integral de la instrucción. Muchas veces estos cambian el número de bytes esperados a continuación (por ejemplo un número de bytes adecuado para operaciones de 32 bits en código de 16 bits).

En pocas palabras, necesitamos escribir un buen "fetcher" de instrucciones, que sea manejable a pesar de la gran cantidad de instrucciones existentes y combinaciones de dichas instrucciones, y operadores.





Voy a seguir escribiendo lo que haga a medida avance. Podría avanzar rápidamente con el código actual, pero sé que es suficientemente fragil como para volverse un problema de escalabilidad o de una correcta emulación, así que voy a irme por el camino más largo e implementar todo pensando en iniciar con las funciones más reutilizables, y una vez que estén bien desarrolladas, construir las capas superiores de la emulación.
#12
Desarrollo Web / Preguntas Básicas sobre jQuery
30 Agosto 2012, 07:07 AM
Preguntas de Programación: jQuery

Pregunta 1. Estoy suponiendo que para jQuery, las tareas se limitan a la siguiente lista de APIs de jQuery. ¿Es así?

jQuery Core, Selectores, Atributos, Traversing, Manipulación, CSS, Eventos, Efectos, Ajax, Utilitidades, jQuery UI

Pregunta 2. ¿Se limita jQuery solo a DHTML, interfaces de usuario y AJAX? ¿Es decir que deja fuera otras cosas como audio, o realmente tiene una forma general de manejar cada etiqueta HTML y propiedad CSS, pero en forma genérica, sin tareas considerablemente más "avanzadas"?

Pregunta 3. ¿Cuáles son las razones principales para usar jQuery aparte de acelerar el desarrollo de interfaces de usuario y no tener que preocuparse por las diferencias de programación de los diferentes navegadores?

Pregunta 4. ¿Cuáles son algunos de los elementos específicos que difieren entre navegadores, o son muchos para ser mencionados aunque sea a grandes rasgos?

Pregunta 5. ¿Debería haber un "Hola Mundo" para cada aspecto de la API?
#13
En este tema pongo microavances directamente aplicables e implementados sobre cómo llevar a cabo una sub-tarea de un sistema mayor.

Hay que aceptar que no hay otra manera de lograr proyectos complejos que no sea basándose en progresos muy pequeños combinables, tomando en cuenta la limitación de la mente humana, que solo puede manejar muy pocas cosas a la vez, y solamente una principal al mismo tiempo, de forma funcional.

Escribir estos micro progresos demuestra que al final del día el avance y la cantidad de logros concretos es mucho mayor que esperando a completar un gran sistema para organizar ese conocimiento y crear un "diccionario" de pequeños trucos de verdades base (ground truths), e igualmente el aprendizaje y la corrección de errores se aceleran.

Como siempre, todo el contenido en este tema, que yo escriba, está bajo licencia de dominio público, y bajo la licencia Creative Commons 0 1.0 Universal (CC0), que equivale al dominio público, con respaldo legal.

Comienzo con un ejemplo de tipo snippet, que resulta ser la base que voy a usar para redirigir ejemplos mediante IDs pasados por URL.

__________________________________________________________

Convirtiendo un Error 404 en una Redirección Sin Error con PHP (Solo para GET, no para POST)


Requerimientos (2):
-PHP 5+
-Servidor configurado con una página PHP personalizada para el Error 404

En PHP, un error 404 hace que perdamos las variables de POST y GET.

Por lo menos, podemos todavía recuperar las variables GET mediante $_SERVER["REDIRECT_QUERY_STRING"] de forma manual, pero hasta donde sé, las variables POST sí se pierden con este método. Para POST, y otros casos, tal vez lo mejor sea usar mod_rewrite, aunque eso requiere ganar experiencia después de mucha prueba, error y entrenamiento, y por eso es que este snippet es valioso para quien no desee o no pueda manejar la complejidad de mod_rewrite.

Si ante un error 404 usamos la función de PHP header("Location: /alguna_URL"); antes de escribir cualquier contenido de documento al cliente, podemos convertir el error 404 No Encontrado en una condición sin error de redirección 301 Movido Permanentemente o 302 Encontrado.

Si a esto le sumamos el manejo manual de $_SERVER["REDIRECT_URL"] para indicar un script no existente, podemos combinar todo esto para crear una URL de búsquedas o de IDs de documento, como por ejemplo:

http://devel.no-ip.org/debree?id=0

En donde /debree no existe, pero que todavía podemos usar con este snippet.

Como se ve, una ventaja de este método es que podemos usar nombres GET de archivos SIN EXTENSIÓN, y sin la necesidad de configuración adicional al servidor, y con la opción de usar este truco o no, cuando lo necesitemos solamente.

Al inicio de nuestra página PHP para el manejo de errores 404, tendríamos:


<?php
//Aquí vamos a manejar el script inexistente
//"/debree":
///
if($_SERVER["REDIRECT_URL"]==="/debree")
{
 
//Como vemos en el IF anterior,
 //$_SERVER["REDIRECT_URL"] solamente contiene
 //el nombre del documento o script, sin contar la
 //parte de la URL para el servidor, y tampoco las
 //variables GET. Esto es ideal para detectar fácilmente
 //si el nombre de script inexistente es el que estamos buscando.
 //
 //Si queremos que no distinga entre mayúsculas y minúsculas, podemos
 //cambiar el código para que las discrimine; pero por ahora distinguir
 //entre unas y otras nos da más posibilidades que si las discrimináramos.
 ///

 //Creamos un arreglo que contiene cada una de
 //las URLs para cada ID de virutas ("debrees" o "debris",
 //un nombre especial para documentos que describen pequeñas
 //combinaciones sintácticas, su valor y efectos, a partir del
 //código de un programa).
 //
 //El ID 0, por "defecto", es el índice de nuestro sitio:
 ///
  
$debrees=Array(
                 
"/"
                
);

 
//Aquí reorganizamos manualmente las variables GET.
 //Reemplazamos todos los '&' por '=', y luego partimos la
 //cadena $_SERVER["REDIRECT_QUERY_STRING"] (la cual contiene
 //las variables URL GET) por cada '='.
 //
 //Con esto, sabemos que la cadena en el elemento de arreglo
 //[$x+0] contiene el nombre de la variable URL GET, y
 //el elemento del arreglo [$x+1] contiene el valor.
 //
 //Más adelante verificamos si realmente existe el valor del
 //parámetro, y si no es así, evitamos seguir.
 //
 //Esta implementación la robusteceremos después, con el tiempo:
 ///
  
$z=str_replace("&""="$_SERVER["REDIRECT_QUERY_STRING"]);
  
$z=explode("="$z);



 
//Esta variable indica si encontramos la viruta deseada.
 //Si la encontramos, se pondrá en TRUE y evitará que mostremos
 //el contenido normal de la página de error 404.
 //
 //Pero si no lo encontramos, permanecerá en FALSE y, convenientemente,
 //desplegaremos el error 404.
 ///
  
$debree_flag_ok=FALSE;

 
//Recorremos todo nuestro arreglo manual de pares
 //de variables/valores GET:
 ///
  
for($x=0;$x<count($z);$x+=2)
  {
   
//Aquí nos interesa encontrar la variable GET "id":
   ///
    
if(strcmp($z[$x],"id")===0)
    {
     
//Si encontramos la variable GET "id", vemos
     //si su valor existe, viendo si tiene una longitud
     //de más de 0 bytes, y después de asegurarnos de eso,
     //vemos que la identificación numérica esté dentro del
     //rango existente de URLs en nuestro arreglo de registros
     //de URL, y que de hecho sea numérica con is_numeric.
     ///
     
if(strlen($z[$x+1])>&& is_numeric($z[$x+1]) && ($z[$x+1]+0)<count($debrees))
     {
      
//Aquí está nuestro truco principal.
      //La siguiente línea convierte el error 404
      //en una redirección:
      ///
        
header("Location: ".$debrees[$z[$x+1]]);

      
//Con esto indicamos que hemos encontrado nuestro
      //documento, y no debemos mostrar el contenido
      //de la página de error 404:
      ///
       
$debree_flag_ok=TRUE;

      
//Detenemos el bucle, para mayor eficiencia, o
      //por lo menos como buena práctica de programación:
      ///
       
break;
     }
    }
  }

 
//Si encontramos nuestra "viruta",
 //nos detenemos aquí para no mostrar
 //el error 404, lo cual no sería correcto
 //en dicha condición.
 ///
  
if($debree_flag_ok) return;
}
?>



Ejemplo de URL que demuestra el uso de este código, que convierte el script inexistente en una URL de consulta válida:

http://devel.no-ip.org/debree?id=0
http://devel.no-ip.org/debree?id=0
http://devel.no-ip.org/debree?id=0
http://devel.no-ip.org/debree?id=0
http://devel.no-ip.org/debree?id=0


Si en lugar de redirigir la URL quisiéramos mostrar contenido válido en la página actual (por ejemplo, para evitar perder la URL escrita originalmente), necesitaríamos esforzarnos más y crear una aplicación PHP completa para el script no existente, manejada desde la página PHP para el manejo del error 404, con los principios que vimos aquí, y emulando un código HTTP 200 OK, que es más difícil de lograr que todo lo anterior, pero que también se logra básicamente con header("HTTP/1.0 200 OK"); y/o similares, además de otros elementos.
#14
El kernel que he escrito y al que me refiero es el del Nivel 1 en este repositorio:

>> Lista de Núcleos de Entrenamiento (solamente Nivel 1 por ahora) <<


El kernel al que me refiero ha llegado a lo que yo llamo el Nivel 1 de desarrollo.

Eso significa que es el nivel mínimo de usabilidad de un núcleo, que pueda serle útil a un usuario.

El nivel mínimo funcionalmente utilizable (Nivel 1) es poder leer programas del directorio raíz de un floppy mediante sus nombres cortos de archivo, enlazado dinámico básico, funciones de sistema exportadas para los programas, entrada de usuario con un teclado PS/2 y una consola de comandos muy básica.

-------------------------

En lo personal, escribir en ensamblador me es bastante fácil, y sería perfecto si el ensamblador x86 se usara por el resto de plataformas.

Pero ya que ese no es el caso, existen lenguajes como C, que tienen convenciones definidas para codificar sus tipos de datos, y llamadas a rutinas, pasado de parámetros, etc.

Este es una pequeña coyuntura clave: Escribí un programa en C que usa las funciones exportardas del kernel. Al comparar la forma en que se escribe un programa en C, su código generado y la falta de convenciones que usan las funciones de mi kernel actual, me llego a dar cuenta que puedo terminar de robustecer mi kernel si insisto en escribir programas en C y en ensamblador, e incluso reescribir el kernel en C y en ensamblador para comparar el código generado, y empezar a adoptar las convenciones, para obtener una portabilidad e interoperabilidad máximas.

Ya que los estándares de C y las convenciones necesarias son muy voluminosas y técnicas, esto no puede tomarse como una adivinanza, así que voy a tener que reunir esos documentos de especificaciones y traducirlos para estudiarlos a profundidad.

También voy a necesitar aprender a programar en C y en ensamblador para más de una plataforma, para poder ser capaz de crear código portable en todos los niveles. Debería por ejemplo aprender una plataforma ARM además de x86-16, x86-32 y x86-64.

-------------------------

Al usar las funciones del kernel como las tengo actualmente, me doy cuenta de que necesito especificar registros del CPU en el código de C a compilarse por GCC. Esto puede hacerse portable si uso mi lenguaje y compilador Real C, pero en GCC eso es un problema de portabilidad de plataformas enorme.

Este es el primer punto en el que voy a robustecer el kernel: Voy a aprender cómo codificar cualquier tipo de parámetros de funciones y variables de todo tipo.

El código de un programa escrito en C requiere más trabajo y más archivos, algo como esto:


"include/external_exported_functions.inc"

;Nota: Este archivo es para ser usado por programas externos,
;      para que sepan dónde encontrar las funciones que desean
;      usar, desde la tabla de funciones exportadas del kernel.

;Estos son los ÍNDICES de cada puntero en la tabla de exportes.
;Las convertimos a posiciones de 4 bytes para programas de 32 bits,
;y a posiciones de 8 bytes para programas de 64 bits.
;;

                           clrscr@KernelCore equ 0
           console_kprint_visible@KernelCore equ 1
           console_doCRLFeffect@KernelCore   equ 2
cmdLine__findFirstBlankSpace@KernelCore      equ 3
cmdLine__findFirstNonBlankSpace@KernelCore   equ 4
adjustCommandLineFATname@KernelCore          equ 5
getCommandLineArgsCount@KernelCore           equ 6
copyCommandLineArg@KernelCore                equ 7
cmdLine__charTypeAt@KernelCore               equ 8
cmdLine__skipNonBlankSpaces@KernelCore       equ 9
cmdLine__skipBlankSpaces@KernelCore          equ 10







"exports.asm"


;Aquí anteponemos un guión bajo a todas las
;funciones de ensamblador a ser llamadas desde C;
;esto es llamado "mangling" o decoración, y es
;una convención de C/el enlazador, para enlazar
;funciones externas al código de C, o entre módulos,
;especialmente entre lenguajes que no comparten las
;convenciones de C, como el caso del ensamblador.
;;

%include "include/external_exported_functions.inc"


global myImportsFunctionsTable
       global _clrscr
       global _console_kprint_visible
       global _console_doCRLFeffect
       global _adjustCommmandLineFATname
       global _getCommandLineArgsCount
       global _copyCommandLineArg
       global _cmdstrbuff


myImportsFunctionsTable:
                   ImportsCount dd 6
                           _clrscr dd clrscr@KernelCore
           _console_kprint_visible dd console_kprint_visible@KernelCore
           _console_doCRLFeffect   dd console_doCRLFeffect@KernelCore
_adjustCommandLineFATname          dd adjustCommandLineFATname@KernelCore
_getCommandLineArgsCount           dd getCommandLineArgsCount@KernelCore
_copyCommandLineArg                dd copyCommandLineArg@KernelCore






_cmdstrbuff times 1024 db 0




"header.asm"


;Aquí hemos optado por establecer a APPBASE
;simplemente a la ubicación actual en el código,
;representada por el signo de dólar, $.
;
;Ahora no es nuestro código en ensamblador el que
;debe encargarse de establecer la dirección base
;del ejecutable, sino que el enlazador LD, por el
;hecho de que estamos usando varios módulos por
;separado, y en esta complejidad solamente el enlazador
;puede llevar a cabo esto eficientemente.
;;
;APPBASE equ 1048576*2
APPBASE equ $

extern myImportsFunctionsTable

;Nuestro kernel debe leer esta dirección, saltar
;a esta y luego saltarse la cabecera del ejecutable:
;;
IntendedBaseAddress  dq APPBASE
NumberOfFieldsBelow  dq 7
CommandLinePtr       dq 0
CommandLineLength    dq 0
CommandLineParamsPtr dq 0
KernelFnExportsTable dq 0
KernelVrExportsTable dq 0
AppFnImportsTable    dq myImportsFunctionsTable
AppVrImportsTable    dq 0



"start.asm"

;Si hay código presente, debemos usar
;BITS 32:
;;
bits 32


;La etiqueta llamada "start"
;debe ser globalmente conocida, para que
;LD o más bien otros módulos de este
;programa pueda encontrarla adecuadamente.
;
;Este es el punto de entrada de nuestra
;aplicación.
;
;"start" es el símbolo que el script LD
;para esta aplicación busca para establecer
;el punto de entrada de la misma, y debe
;declararse como global.
;;
global start



;Estas son las funciones del kernel, con
;un guión bajo al inicio ("mangled") para
;que C pueda encontrarlas.
;
;Indicamos que son externas porque estos símbolos
;están definidos en "exports.asm":
;;
extern _clrscr
extern _console_kprint_visible
extern _console_doCRLFeffect
extern _adjustCommmandLineFATname
extern _getCommandLineArgsCount
extern _copyCommandLineArg






start:

;Limpiamos la pantalla como siempre:
;;
call dword[_clrscr]

;Declaramos el símbolo "_main" como
;externo, ya que se encuentra en "main.c",
;y llamamos a main, que está declarado como
;int main(void), al menos de acuerdo a nuestro
;kernel actual y también para esta aplicación
;específica.
;
;Debemos aprender a implementar
;int main(int argc, char **argv)
;por nosotros mismos:
;;
extern _main
call _main


;Aquí le devolvemos el control
;al kernel:
;;
ret




"main.c"

//Ya que nuestras funciones importadas
//están en una tabla de punteros de funciones,
//debemos declarar la función como un puntero
//a una función, para generar el código adecuado:
///
extern void (*console_doCRLFeffect)(void);


int main(void)
{
//Aquí colocaremos una lista de instrucciones
//para demostrar la sintaxis de AT&T de GAS
//para ensamblador inline, de todas las
//combinaciones de opcodes y expresiones que
//sea útil recordar:
///
  __asm__ __volatile__ ("pushl %eax");
  __asm__ __volatile__ ("popl %eax");


//Llamamos nuestra función proveniente
//del kernel. Ya que esta no toma parámetros,
//podemos usarla libremente sin temor a
//un mal manejo de los parámetros y la pila.
//Pero esto será un problema para funciones de
//la librería del kernel que usen parámetros, a
//menos que estén totalmente de conformidad a
//las convenciones de C (cdecl):
///
  console_doCRLFeffect();

//Devolvemos 0 desde main, que en las x86
//lo coloca en AX/EAX/RAX:
///
  return 0;
}



"link.ld"

OUTPUT_FORMAT("binary")
ENTRY(start)
phys = 0x0000000000200000;
SECTIONS
{
  .text phys : AT(phys) {
    code = .;
    *(.text)
    *(.rodata)
    . = ALIGN(0);
  }
  .data : AT(phys + (data - code))
  {
    data = .;
    *(.data)
    . = ALIGN(0);
  }
  .bss : AT(phys + (bss - code))
  {
    bss = .;
    *(.bss)
    . = ALIGN(0);
  }
  end = .;
}



"build.bat"

nasm -f aout -o header.o header.asm
nasm -f aout -o start.o start.asm
gcc -Wall -O -fstrength-reduce -fomit-frame-pointer -finline-functions -nostdinc -fno-builtin -c -o main.o main.c
nasm -f aout -o exports.o exports.asm

ld -T link.ld -o kern0 header.o start.o main.o exports.o



En "build.bat" (o un script Bash de Linux), el orden en el que se compilan los diferentes componentes es arbitrario; pero el orden en que se enlazan con LD es físicamente el mismo que el especificado en la línea de comandos, y debe estar en el orden mostrado aquí (cabecera del programa, inicializador en ensamblador, programa principal, otros archivos de código opcionales, y la tabla de exportes).

link.ld está configurado para generar un archivo binario crudo, y usar una alineación de 0 entre secciones.

Con un script más personalizado, podríamos indicar un ejecutable crudo pero encargarnos nosotros mismos de generar a mano el formato del ejecutable (PE, ELF, AOUT, MZ-EXE, etc.).

Ya que estamos usando el formato AOUT para crear el código objeto de cada pieza del programa mostrado aquí, también deberíamos aprender a manejar dicho formato a bajo nivel, para eventualmente crear herramientas propias y llevar a cabo tareas de depuración y desarrollo más potentes.
#15
Como nota inicial, si alguien no tiene una mejor idea de cuál sería la mejor forma de que escriba varios posts como respuestas seguidas, incluso quizás después de varias semanas, pido disculpas si envío respuestas a este tema o abro otros nuevos, porque seguramente va a ser mucha la complejidad a manejar, y repartir las diferentes etapas de descubrimientos es mucho más fácil repartiéndolas en diferentes posts, temas y/o respuestas (que serían continuas a menos que alguien responda o consulte algo, o tenga una idea de qué más averiguar o hacer algo interesante y útil con todo esto desde ya, aparte obviamente de realmente aprender Java).

Me tomo la libertad de escribir sobre la programación en ensamblador, pero en el lenguaje dictado por el bytecode de Java.

Las razones más importantes de esto son:

- Para personas demasiado acostumbradas a trabajar con lenguajes al nivel de C o más bajos, trabajar con un ensamblador en un entorno nativo a la orientación a objetos hace mucho más fácil entender a cabalidad cómo funciona realmente la orientación a objetos, en este caso, de Java.

- Dado que Java es una plataforma unificada sin importar el hardware sobre el que corra, estudiarlo a nivel de ensamblador es una oportunidad excepcionalmente buena para practicar la ingeniería inversa y obtener un nivel de experticia por lo menos intermedio.

- Siendo expertos en el ensamblador de Java y en el formato de archivos de bytecode (.class), así como en el uso de las diferentes APIs y teniendo experticia suficiente para escribir un compilador no optimizador como mínimo, se puede dejar de usar el lenguaje Java para producir programas de Java, y eventualmente es posible usar virtualmente cualquier otro lenguaje de programación (incluso ensamblador de Intel x86, e incluso enmascarando las APIs de Java para usarlas como "alias" de otras plataformas como WinAPI o javascript, y así "recortar" un poco lo que se necesita aprender, y unificar un mismo conocimiento en diferentes ambientes de desarrollo). Esto puede llegar a ser especialmente útil, porque significaría que muchos programas escritos lenguajes que tradicinalmente tienen poca o ninguna portabilidad entre plataformas de hardware pueden reutilizarse, convirtiéndolos en instrucciones de bytecode de Java.

- El ensamblador de Java es extremadamente valioso. Los lenguajes de ensamblador "normales" son evitados por la mayoría de programadores no solo por su complejidad, sino que por el hecho de que no están pensados para ser portables. Con Java, los programas generados son más simples que los ejecutables ELF de Linux, y el ensamblador que se escriba en una plataforma, puede correr en cualquier otra en la que haya una JVM. Eso significa que se pueden hacer tareas interesantes de muy bajo nivel, que al mismo tiempo incluyan programación "moderna" orientada a objetos, con la posibilidad de poder seguir corriendo el mismo código en otras plataformas.


Todo esto suena muy interesante, pero para lograrlo, siendo indistintamente buenos programadores de C/ensamblador por ejemplo, o buenos programadores de Java (aunque a un nivel común y corriente, no a nivel de ensamblador y de la arquitectura central), este proceso puede llevar no menos de un año, durante el que hay que releer cosas como el Tutorial de Java, compilar los programas de ejemplo, hacer ingeniería inversa intensa y desensamblarlos (NO decompilarlos, sino que inspeccionar los archivos binarios a mano si es posible y/o hacer un parser), y leer una y otra vez las partes de las especificaciones que se están aplicando en cada ejemplo compilado.

------------------------------------------------------
------------------------------------------------------
------------------------------------------------------
------------------------------------------------------

Pongo un ejemplo simple de un Hola Mundo, como el del Tutorial de Java, pero en Ensamblador de Java.

No he usado un ensamblador nativo de Java "apropiado" sino que NASM, que entre otras cosas no permite usar Big Endian (Java) sino solo Little Endian (x86), así que se ve rápidamente la necesidad de usar un programa ensamblador ya sea de ARM que use Big Endian por defecto, crear un ensamblador propio para Java (en javascript por ejemplo), o buscar un ensamblador "apropiado" nativo a Java.

Esto debe compilarse con lo siguiente, ya sea en Windows, Linux, etc.:

nasm EHLOWorldApp.asm -o EHLOWorldApp.class



;/*****************************************************************************
;EHLOWorldApp.java
;
; 2012-07-02
;
;
;Demostración inicial de un programa de Java escrito totalmente en ensamblador
;(ensamblador de Java, pero usando NASM para codificar los bytes).
;
;http://devel.cable-modem.org/
;
;Este código es de dominio público (sin derechos de autor).
;Puedes hacer lo que desees con él.
;
;
;*****************************************************************************/


_CLASS_START:

_00000000__magic db 0xCA,0xFE,0xBA,0xBE


_00000004__minor_version dw 0x0000


_00000006__major_version db 0x00,0x33


_00000008__constant_pool_count db 0,29+1

   _0000000A__cp_info_0001:
                          db 0x0A    ;cp_info.tag: CONSTANT_Methodref
                          db 0,0x06  ;cp_info.info.class_index
                          db 0,0x0F  ;cp_info.info.name_and_type_index

   _0000000F__cp_info_00002:
                          db 0x09    ;cp_info.tag: CONSTANT_Fieldref
                          db 0,0x10  ;cp_info.info.class_index
                          db 0,0x11  ;cp_info.info.name_and_type_index

   _00000014__cp_info_0003:
                          db 0x08    ;cp_info.tag: CONSTANT_String
                          db 0,0x12  ;cp_info.info.string_index

   _00000017__cp_info_0004:
                          db 0x0A    ;cp_info.tag: CONSTANT_Methodref
                          db 0,0x13  ;cp_info.info.class_index
                          db 0,0x14  ;cp_info.info.name_and_type_index

   _0000001C__cp_info_0005:
                          db 0x07    ;cp_info.tag: CONSTANT_Class
                          db 0,0x15  ;cp_info.info.name_index

   _0000001F__cp_info_0006:
                          db 0x07    ;cp_info.tag: CONSTANT_Class
                          db 0,0x16  ;cp_info.info.name_index

   _00000022__cp_info_0007:
                          db 0x01     ;cp_info.tag: CONSTANT_Utf8
                          db 0,0x06   ;cp_info.info.length
                          db "<init>" ;cp_info.info.bytes[length]

   _0000002B__cp_info_0008:
                          db 0x01     ;cp_info.tag: CONSTANT_Utf8
                          db 0,0x03   ;cp_info.info.length
                          db "()V"    ;cp_info.info.bytes[length]

   _00000031__cp_info_0009:
                          db 0x01     ;cp_info.tag: CONSTANT_Utf8
                          db 0,0x04   ;cp_info.info.length
                          db "Code"   ;cp_info.info.bytes[length]

   _00000038__cp_info_000A:
                          db 0x01     ;cp_info.tag: CONSTANT_Utf8
                          db 0,0x0F   ;cp_info.info.length
                          db "LineNumberTable"   ;cp_info.info.bytes[length]

   _0000004A__cp_info_000B:
                          db 0x01     ;cp_info.tag: CONSTANT_Utf8
                          db 0,0x04   ;cp_info.info.length
                          db "main"   ;cp_info.info.bytes[length]

   _00000051__cp_info_000C:
                          db 0x01     ;cp_info.tag: CONSTANT_Utf8
                          db 0,0x16   ;cp_info.info.length
                          db "([Ljava/lang/String;)V"   ;cp_info.info.bytes[length]

   _0000006A__cp_info_000D:
                          db 0x01     ;cp_info.tag: CONSTANT_Utf8
                          db 0,0x0A   ;cp_info.info.length
                          db "SourceFile"   ;cp_info.info.bytes[length]

   _00000077__cp_info_000E:
                          db 0x01     ;cp_info.tag: CONSTANT_Utf8
                          db 0,0x11   ;cp_info.info.length
                          db "EHLOWorldApp.java"   ;cp_info.info.bytes[length]

   _0000008B__cp_info_000F:
                          db 0x0C     ;cp_info.tag: CONSTANT_NameAndType
                          db 0,0x07   ;cp_info.info.name_index
                          db 0,0x08   ;cp_info.info.descriptor_index

   _00000090__cp_info_0010:
                          db 0x07    ;cp_info.tag: CONSTANT_Class
                          db 0,0x17  ;cp_info.info.name_index

   _00000093__cp_info_0011:
                          db 0x0C     ;cp_info.tag: CONSTANT_NameAndType
                          db 0,0x18   ;cp_info.info.name_index
                          db 0,0x19   ;cp_info.info.descriptor_index

   _00000098__cp_info_0012:
                          db 0x01     ;cp_info.tag: CONSTANT_Utf8
                          db 0,0x0C   ;cp_info.info.length
                          db "Hello World."   ;cp_info.info.bytes[length]

   _000000A6__cp_info_0013:
                          db 0x07    ;cp_info.tag: CONSTANT_Class
                          db 0,0x1A  ;cp_info.info.name_index

   _000000A9__cp_info_0014:
                          db 0x0C     ;cp_info.tag: CONSTANT_NameAndType
                          db 0,0x1B   ;cp_info.info.name_index
                          db 0,0x1C   ;cp_info.info.descriptor_index

   _000000AE__cp_info_0015:
                          db 0x01     ;cp_info.tag: CONSTANT_Utf8
                          db 0,0x0C   ;cp_info.info.length
                          db "EHLOWorldApp"   ;cp_info.info.bytes[length]

   _000000BD__cp_info_0016:
                          db 0x01     ;cp_info.tag: CONSTANT_Utf8
                          db 0,0x10   ;cp_info.info.length
                          db "java/lang/Object"   ;cp_info.info.bytes[length]

   _000000D0__cp_info_0017:
                          db 0x01     ;cp_info.tag: CONSTANT_Utf8
                          db 0,0x10   ;cp_info.info.length
                          db "java/lang/System"   ;cp_info.info.bytes[length]

   _000000E3__cp_info_0018:
                          db 0x01     ;cp_info.tag: CONSTANT_Utf8
                          db 0,0x03   ;cp_info.info.length
                          db "out"   ;cp_info.info.bytes[length]

   _000000E9__cp_info_0019:
                          db 0x01     ;cp_info.tag: CONSTANT_Utf8
                          db 0,0x15   ;cp_info.info.length
                          db "Ljava/io/PrintStream;"   ;cp_info.info.bytes[length]

   _00000101__cp_info_001A:
                          db 0x01     ;cp_info.tag: CONSTANT_Utf8
                          db 0,0x13   ;cp_info.info.length
                          db "java/io/PrintStream"   ;cp_info.info.bytes[length]

   _00000117__cp_info_001B:
                          db 0x01     ;cp_info.tag: CONSTANT_Utf8
                          db 0,0x07   ;cp_info.info.length
                          db "println"   ;cp_info.info.bytes[length]

   _00000121__cp_info_001C:
                          db 0x01     ;cp_info.tag: CONSTANT_Utf8
                          db 0,0x15   ;cp_info.info.length
                          db "(Ljava/lang/String;)V"   ;cp_info.info.bytes[length]

                       __1D:
                          db 0x08    ;cp_info.tag: CONSTANT_String
                          db 0,0x12  ;cp_info.info.string_index




_00000139__access_flags:
                      db 0x00,0x20


_0000013B__this_class:
                      db 0x00,0x05

_0000013D__super_class:
                      db 0x00,0x06

_0000013F__interfaces_count:
                      db 0x00,0x00

;interfaces ------- no interfaces


_00000141__fields_count:
                      db 0x00,0x00


;field_info ------- no fields


_00000143__methods_count:
                      db 0x00,0x02


       _00000145__method_info_0001:
                              db 0x00,0x00     ;access_flags
                              db 0x00,0x07     ;name_index
                              db 0x00,0x08     ;descriptor_index
                              db 0x00,0x01     ;attributes_count
                                  db 0x00,0x09   ;code_attribute/attribute_info[0].attribute_name_index
                                  db 0x00,0x00,0x00,(0x1D)   ;code_attribute/attribute_info[0].attribute_length

                                  db 0X00,0X01       ;code_attribute.max_stack
                                  db 0X00,0X01       ;code_attribute.max_locals
                                  db 0X00,0X00,0X00,0X05   ;code_attribute.code_length

                                     ;INIT: Instructions
                                     ;INIT: Instructions
                                     ;INIT: Instructions
                                     ;INIT: Instructions

                                       db 0X2A         ;aload_0

                                       db 0XB7         ;invokespecial #1
                                       db 0X00
                                       db 0X01

                                       db 0XB1         ;return

                                     ;END: Instructions
                                     ;END: Instructions
                                     ;END: Instructions
                                     ;END: Instructions



                                  db 0X00,0X00    ;code_attribute.exception_table_length


                                  db 0X00,0x01    ;code_attribute.attributes_count       ;1

                                      db 0X00,0X0A             ;LineNumberTable_attribute/attribute_info.attribute_name_index
                                      db 0X00,0X00,0X00,0X06   ;LineNumberTable_attribute/attribute_info.attribute_length
                                          db 0X00,0X01       ;LineNumberTable_attribute.line_number_table_length
                                              db 0X00,0X00       ;line_number_table[0].start_pc
                                              db 0X00,0X05       ;line_number_table[0].line_number


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
       _00000170__method_info_0002:
                              db 0x00,0x09     ;access_flags
                              db 0x00,0x0B     ;name_index
                              db 0x00,0x0C     ;descriptor_index
                              db 0x00,0x01     ;attributes_count
                                  db 0x00,0x09   ;code_atribute/attribute_info[0].attribute_name_index
                                  db 0x00,0x00,0x00,(0x25)   ;code_atribute/attribute_info[0].attribute_length
x17E:
                                  db 0x00,0x02      ;code_attribute.max_stack
                                  db 0x00,0x01      ;code_attribute.max_locals
                                  db 0x00,0x00,0x00,(0x09)  ;code_attribute.code_length

                                     ;INIT: Instructions
                                     ;INIT: Instructions
                                     ;INIT: Instructions
                                     ;INIT: Instructions


                                       db 0xB2      ;getstatic #2
                                       db 0x00
                                       db 0x02

                                       db 0x12      ;ldc #3
                                       db 0x1D

                                       db 0xB6      ;invokevirtual #4
                                       db 0x00
                                       db 0x04

                                       db 0xB1      ;return

                                     ;END: Instructions
                                     ;END: Instructions
                                     ;END: Instructions
                                     ;END: Instructions

                                  db 0x00,0x00      ;code_attribute.exception_table_length


                                  db 0x00,0x01      ;code_attribute.attributes_count    ;1

                                      db 0x00,0x0A              ;LineNumberTable_attribute/attrbute_info.attribute_name_index
                                      db 0x00,0x00,0x00,0x0A    ;LineNumberTable_attribute/attribute_info.attribute_length
                                            db 0x00,0x02       ;LineNumberTable_attribute.line_number_table_length
                                                db 0x00,0x00       ;line_number_table[0].start_pc
                                                db 0x00,0x07       ;line_number_table[0].line_number

                                                db 0x00,0x08       ;line_number_table[1].start_pc
                                                db 0x00,0x08       ;line_number_table[1].line_number



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
f_000001A3__attributes_count db 0x00,0x01     ;attributes_count           ;1
                               db 0x00,0x0D   ;SourceFile_attribute/attribute_info[0].attribute_name_index
                               db 0x00,0x00,0x00,0x02   ;SourceFile_attribute/attribute_info[0].attribute_length


                               db 0x00,0x0E         ;SourceFile_attribute.sourcefile_index




Y el código equivalente en Java normal:


class EHLOWorldApp
{
public static void main(String[] args)
{
 System.out.println("Hello World.");
}
}




Planeo poco a poco documentar y explicar lo que está pasando, aunque ya que he comentado prácticamente todas las líneas en ensamblador, obviamente entiendo lo que está pasando.

Aunque necesito formalizar las explicaciones, porque voy a necesitarlo cuando trate escribir un ensamblador especial para Java y cuando quiera implementar un compilador de un lenguaje que no sea Java, pero que produzca programas para Java.


------------------------------------------------------
------------------------------------------------------
------------------------------------------------------
------------------------------------------------------




Referencias

Seguir las especificaciones es relativamente fácil para quienes, como yo, están acostumbrados a examinar de forma permanente la estructura de todos los archivos en su computadora, a hacer encajar exactamente cada pieza de un programa en ensamblador (lo que permite encontrar mucho más rápidamente la causa de errores causados por dos o más valores interdependientes) y a pensar en términos de cómo las especificaciones combinan los datos requeridos para una tarea en estructuras de todo tipo (y teniendo en mente qué pudieron haber estado pensando los desarrolladores de dichos estándares para hacer las cosas de la forma en que las hicieron de entre muchos diseños posibles e incluso mucho más simplificados).

Como dije, una de las intenciones principales de todo esto es eventualmente poder escribir programas de Java con lenguajes "normales", como C, Visual Basic, Pascal, etc.

Pero para eso se necesita tener gran experticia en el ensamblador de Java, y en la estructura de bajo nivel del lenguaje, las clases, y todos los demás aspectos de la máquina virtual de Java, para poder crear equivalentes para hacer que de un lenguaje no oficial se pueda producir bytecode apropiado y totalmente correcto.

Esta es la lista de lo que hay que empezar a leer, y no hay que olvidar tampoco las referencias de las diferentes APIs, y también el tutorial de Java, que sería extremadamente interesante "remasterizar" en su versión en ensamblador Java, para comprender cada detalle de lo que contiene y hacer posible que se convierta en un libro de alto nivel capaz de volver a un programador en un experto absoluto en Java, ya sea programando en alto nivel o en el nivel más bajo posible:


Especificaciones de bajo nivel de Java

El capítulo 4 habla específicamente del formato de los archivos .class


Wikipedia: Formato de los archivos .class

Wikipedia: Resumen del bytecode de Java

Wikipedia: Resumen del conjunto de instrucciones de Java


También vale la pena mencionar el comando básico del desensamblador del JDK:

javap -c EHLOWorldApp.class
#16
Como había mencionado hace un par de semanas, quería implementar un programa de bajo nivel que fuera simple pero a la vez útil, y para eso era necesario que fuera capaz de correr programas externos.

Por ahora, solamente pueden leerse archivos de una disquetera interna, no una USB.

Poco a poco voy a explicar e indexar la información de cómo hace cada cosa, pero a la vista del usuario este programa es como una versión Alpha de una consola de MS-DOS en su primera versión, la primera de todas, así que tiene soporte para:

- Teclado
- Pantalla de texto
- Correr programas de 32 bits desde la disquetera
- El sistema exporta funciones y variables, para que los programas externos no tengan que reimplementar la misma funcionalidad. Poco a poco voy a migrar la funcionalidad de programas externos que demuestren ser valiosos al núcleo mismo del sistema.



Lo bueno de esto es que con la capacidad de correr programas externos, se puede llevar a cabo absolutamente cualquier tarea, por ejemplo, correr un programa binario compilado en C desde Windows/Linux, que active el modo gráfico, que genere algún gráfico, y que desee guardarlo a la disquetera.

O un intérprete increíblemente simple de mi lenguaje Real C, o para entrar en estándar, un intérprete de javascript que comience con funciones como alert, el operador typeof y la declaración de variables, etc...

Con esto se hace fácil estudiar minuciosamente cualquier tarea de programación, a un grado excepcional, y todos los detalles aprendidos, usarlos para optimizar y de hecho comprender la creación de aplicaciones en sistemas ya establecidos, como Windows, Linux, Mac, etc.

Este grupo de temas que pienso poner sí va a ser lo más dinámico y prolífico que probablemente haya hecho hasta ahora en mi vida en la Web, ya que este estudio lo llevo a cabo durante todo el día, todos los días (a menos que necesite descansar), así que pido que me tengan "paciencia".

Pero lo que sí puedo prometer es que esto va a ser interesante y provechoso y poco a poco debería ser capaz de demostrar que esto es en enorme medida, inmediatamente aplicado a cualquier plataforma de computadoras.



---------------------------------------------------------------


Empiezo con el código más básico.

La pregunta es, ¿qué les parece el código fuente que he escrito hasta ahora? ¿Qué podría hacer para que sea más legible? ¿Qué idea tienen para hacer algo útil? Lo próximo que se me ocurre en lo personal es discutir programas de C con complejidad cada vez mayor, vista desde el punto de vista de un compilador, no solo compilarlos, y cómo interactúan con la máquina.

>> Muestra de un Sistema Ejecutivo Básico <<


También, empiezo inmediatamente a ver cuál es la siguiente tarea que debería llevar a cabo en lo poco que me queda de hoy.