1 puntos por GN⁺ 2023-10-16 | 1 comentarios | Compartir por WhatsApp
  • Lotus 1-2-3, una hoja de cálculo propietaria de hace 30 años, logró ejecutarse de forma nativa en Linux gracias a materiales recuperados por casualidad y hacking de binarios, pese a que Linux no existía cuando fue lanzada
  • El hallazgo del SDK de add-ins LPL que se creía perdido y de Lotus 1-2-3 for UNIX en respaldos de BBS de los años 90 permitió compilar plugins de ejemplo y analizar los binarios de UNIX
  • La distribución de UNIX incluía un objeto COFF de Intel 80386 comprimido, 123.o, y unos 20,000 símbolos junto con información de depuración que dejaron ver su estructura interna
  • El port no se resolvió solo convirtiendo COFF a ELF: también hubo que sortear las diferencias de ABI en llamadas al sistema y estructuras entre Linux y UNIX con coffsyrup y funciones wrapper
  • El port actual corre sin caídas y es 100% usable, aunque todavía quedan algunos detalles y el port del driver de terminal; por ahora la versión DOS en emulación sigue viéndose mejor

El punto de partida para portar una app propietaria de hace 30 años a Linux

  • Lotus 1-2-3 seguía como abandonware de hace 30 años, pero varios hallazgos y hacks hicieron posible un port nativo a Linux
  • El objetivo del port es el clásico Lotus 1-2-3 R3, aunque Lotus 1-2-3 siguió teniendo lanzamientos hasta 2002
  • Este proyecto surgió del trabajo de mantenimiento del driver lotusdrv, que hace que Lotus 1-2-3 funcione bien en sistemas modernos
    • La API del driver se entendió mediante ingeniería inversa, y los drivers existentes funcionan bien en sistemas actuales

El SDK LPL perdido y los respaldos de BBS

  • Lotus 1-2-3 estaba diseñado para ampliarse con plugins, es decir, add-ins, pero estos debían escribirse en un lenguaje especial llamado LPL
  • El compilador de LPL y el SDK estaban perdidos, y Lotus no distribuía el SDK gratis: lo vendía por 395 dólares
  • Un ex sysop que conservaba respaldos en cinta de sistemas BBS de los años 90 recuperó una copia warez del SDK
    • El ADK recuperado puede descargarse como 123DADK.ZIP
    • Un programa de ejemplo en LPL está publicado como modern.pl
  • En esos mismos respaldos de BBS también apareció una copia warez de Lotus 1-2-3 for UNIX, que se consideraba ampliamente perdida

Análisis de las imágenes de disco de Lotus 1-2-3 for UNIX

  • La versión para UNIX sobrevivía como un conjunto de archivos TD0 desde 123UNIX1.TD0 hasta 123UNIX5.TD0
  • Se confirmó que TD0 era un viejo formato comprimido de imagen de disco de los años 80, y se usó samdisk para convertirlo a imágenes de disco raw
  • De las imágenes convertidas, la primera resultó ser un tar archive, y las demás eran ASCII cpio archive en formato pre-SVR4 u odc
  • Las imágenes completas de disco fueron subidas a Internet Archive
  • Al descomprimirlas, bajo lotus/123.v10 aparecieron ejecutables, ayuda, keymaps, datos de drivers de impresora y video, archivos de ejemplo, manuales y más
    • En total, la estructura tenía unas 35 carpetas y 338 archivos

123.o, la pista decisiva

  • En el directorio sysV386/lib se encontró un archivo grande dividido en 123.o.z_1 y 123.o.z_2
  • Al unir ambas partes y descomprimirlas, se confirmó que 123.o era un archivo objeto COFF de Intel 80386
    • Un archivo objeto sin strip
    • 5 secciones
    • Offset de símbolos 0x1efbdc
    • 19,755 símbolos

      • tamaño del encabezado opcional: 28
      • Este archivo incluía símbolos privados e información de depuración, lo que ayudó enormemente a entender la estructura interna de Lotus 1-2-3
      • La respuesta recibida en alt.folklore.computers apuntó a que el archivo no estaba ahí por error
      • Como dlopen() no era de uso extendido en el UNIX de inicios de los 90, probablemente era un objeto parcialmente enlazado para extensiones y relinkeo

La información de depuración dejó ver la estructura interna

  • La versión UNIX era muy cercana a un port directo del código fuente de la versión DOS, así que gran parte funcionaba del mismo modo
  • La información de depuración incluida resolvió varias dudas sobre el interior de Lotus 1-2-3
  • Para mejorar la salida de gráficos se quería enganchar el driver al rasterizer, pero solo con la documentación era difícil entender su funcionamiento
  • Gracias a la depuración se descubrió que el rasterizer genera dinámicamente un pequeño programa de bytecode, que luego el motor gráfico interpreta
  • Una vez conocidos los opcodes, fue posible desensamblarlos y modificarlos en raster.c para mejorar la salida

Convertir de COFF a ELF

  • objcopy puede convertir archivos objeto COFF al formato ELF que usa Linux
  • Se convirtió 123.o a 123elf.o con el comando objcopy -I coff-i386 -O elf32-i386 123.o 123elf.o
  • El resultado se identificó como ELF 32-bit LSB relocatable, Intel 803386, version 1 (SYSV), not stripped
  • Según objdump, la hora de compilación del archivo objeto original fue 8 de septiembre de 1990, 06:23:50, antes de que existiera la primera versión de Linux

Manejo de las diferencias de ABI entre Linux y UNIX

  • El primer problema fue que Linux y UNIX no usan una interfaz de llamadas al sistema compatible entre sí
  • La versión UNIX usaba la interfaz lcall7; por ejemplo, open() llamaba a una callgate con la forma call 0x7:0x0
  • Como Linux no soporta esa callgate, al ejecutarlo tal cual el programa se caía
    • Linux alguna vez tuvo compatibilidad con lcall7 y lcall27, pero ya no
  • El objetivo era eliminar esas llamadas y redirigir todas a través de glibc

Reubicaciones y coffsyrup

  • Primero se intentó quitar el símbolo con objcopy --strip-symbol open, pero objcopy lo rechazó porque open se usaba en una relocation
  • Un archivo objeto relocatable incluye referencias simbólicas e información de reubicación para poder cargarse y funcionar en cualquier dirección
  • Para eliminar un símbolo, también hay que modificar la información de reubicación que lo referencia
  • Para eso se escribió una pequeña herramienta llamada coffsyrup
    • Puede quitar símbolos COFF que objcopy se niega a eliminar
    • Por ejemplo, permite localizar el símbolo open y las relocations relacionadas para procesarlas

Funciones de UNIX que no son compatibles a nivel binario

  • Muchas funciones estándar de UNIX son compatibles a nivel de código fuente, pero no a nivel binario
  • El ejemplo típico es struct stat
    • El mismo código en C puede compilarse en varios sistemas UNIX
    • Pero el archivo objeto compilado puede romperse en otro sistema por diferencias en el tamaño de struct stat o en el offset de st_size
  • Entre las funciones principales que hubo que tratar están stat(), times(), uname(), fcntl() e ioctl()
  • El enfoque fue renombrar símbolos con objcopy, marcarlos como undefined con coffsyrup, y escribir funciones wrapper que convierten estructuras de Linux a estructuras UNIX
  • termios fue un obstáculo especialmente grande: su comportamiento detallado varía sutilmente entre sistemas UNIX y no es compatible, lo que hizo difícil depurarlo

Verificación de licencia y resultado final

  • Después de varios hacks, el programa ya corría sin caerse, pero no funcionaba sin una licencia
  • Poniendo un breakpoint en exit(), se identificó que el símbolo interno que comprobaba una licencia válida era lic_init()
  • Al revisar el código con IDA, se vio que la verificación buscaba el archivo LICENSE.000 y comprobaba si la fecha de vencimiento, el nombre de usuario y el nombre del sistema coincidían con los valores reportados por el sistema
  • Finalmente, Lotus 1-2-3 quedó porteado al nuevo sistema operativo Linux
  • El estado actual es el siguiente
    • Corre sin caídas
    • 100% usable

      • Aún faltan algunos ajustes finos
      • Queda pendiente portar el driver de terminal
      • Por ahora, la versión DOS ejecutada en emulación todavía se ve mejor, aunque eso puede corregirse
      • El código del port está publicado en github

1 comentarios

 
GN⁺ 2023-10-16
Opiniones en Hacker News
  • Es casi increíble que hayan recuperado una copia warez del SDK desde un respaldo en cinta de un viejo sistema BBS y hasta hayan compilado el plugin de ejemplo.
    Me hizo pensar en Why History Needs Software Piracy

    • Quería crear un archivo de preservación a largo plazo que reuniera manuales, actualizaciones de firmware, drivers y utilidades para sintetizadores, equipos Eurorack y similares que se venden actualmente.
      Como estos equipos son hardware que seguirá existiendo durante décadas, tendría mucho valor público contar con un repositorio centralizado y duradero que toda la comunidad pudiera usar, más allá de que cada fabricante guarde cosas en su nube privada.
      También pensé en distribuir el archivo cada año, o vender Blu-ray archivísticos en medios físicos capaces de durar unos 100 años.
      Así, la probabilidad de que alguien tenga ese último archivo .bin raro necesario para revivir el firmware dañado de un módulo Eurorack DSP basado en ARM se acercaría a 1.
  • Mi padre tenía un montón de archivos de Lotus 1-2-3 importantes en una laptop secundaria con un Windows viejo, y como a veces necesitaba abrirlos, la situación era bastante preocupante.
    Hace poco descubrí que LibreOffice puede convertir archivos de Lotus a ODF/ODS, incluso desde la línea de comandos, y los convertí todos con un script sencillo en bash.
    Subí en lote los archivos convertidos a Nextcloud con Collabora, le di a mi padre una cuenta y una guía rápida de uso, y ahora puede ver los archivos en línea; además, quedan incluidos en la rutina normal de respaldos del servidor.
    Muchas gracias a los arqueólogos de datos como el OP y a los colaboradores de LibreOffice.

    • Me da bastante curiosidad qué tipo de archivos son, para que sigan siendo importantes después de tanto tiempo.
  • Me recordó cuando tenía 7 años y le pedí a mi padre un Nintendo, pero en su lugar me compró una PC 286 con Lotus 1-2-3 y la aventura de texto de Indiana Jones.

    • En el Computer Museum de Boston vi una LISP Machine que se veía increíble y dije que quería una, pero al final recibí una Commodore 64.
      Por eso mi primer lenguaje fue BASIC y no LISP, y pienso culpar a esta tragedia de todos mis fracasos en la vida; no aceptaré objeciones.
    • Le rogué que me comprara un NES, pero mi padre me dio una C64 diciendo “esto es mejor; algún día lo entenderás”, y al final me cambió la vida.
    • Quería una BBC Micro, pero recibí una ZX Spectrum, y al final fue mucho mejor para despertar mi interés por la programación.
      Incluso si la Spectrum ya estaba en decadencia para entonces.
    • Recibí una Apple IIgs y Leisure Suit Larry, pero ni mi hermano mayor ni yo podíamos responder de forma confiable las preguntas de verificación de edad que aparecían al inicio.
  • Estoy haciendo algo parecido, pero agregando un paso para convertir primero partes del programa en archivos objeto.
    Así no quedo atado solo a los archivos objeto existentes, aunque hace falta algo de ingeniería inversa para que funcione.
    Hice una prueba de concepto con aln, el enlazador de Atari Jaguar: separé un ejecutable a.out de Linux x86 en archivos objeto ELF y luego lo reenlacé como ejecutable ELF x86 sorteando las diferencias de ABI.
    https://forums.atariage.com/topic/354341-porting-the-original-atari-jaguar-sdk-to-elf/

  • Fue interesante en muchos sentidos.
    El proceso de pasar de un binario de UNIX a un binario de Linux sin código fuente, ni el compilador original, ni el lenguaje original, me pareció genial; este es el tipo de contenido propio de HN.
    También recuerda que en 2023 Usenet sigue usándose para algo más que distribuir archivos rar.
    Y trae a la memoria cómo, antes de que internet se popularizara, la cultura BBS difundió al público el entusiasmo y una excelente distribución de shareware.

    • Siento que el espíritu BBS está regresando.
      Más aún viendo cómo se desmoronan Twitter y otras redes sociales; los centennials más grandes están fascinados con la nostalgia de los 80 y 90, incluso descargando sonidos de negociación de módem como tono de llamada.
      Mi sobrino de 23 años hizo eso hace poco, y obras como American Horror Story o Stranger Things siguen alimentando esa nostalgia.
      Parece que el viejo dicho es cierto: si esperas lo suficiente, todo vuelve a estar de moda.
  • También hubo una buena discusión en mayo de 2022 del año pasado.
    https://news.ycombinator.com/item?id=31455968

  • El enlace a https://scenelist.org/ en este excelente artículo fue justo la bomba de nostalgia que necesitaba esta mañana.
    Es un gran viaje al pasado; muy recomendable.

  • Enlaces relacionados:
    Lotus 1-2-3 for Linux - https://news.ycombinator.com/item?id=35807639 - mayo de 2023, 73 comentarios
    Lotus 1-2-3 - https://news.ycombinator.com/item?id=35872758 - mayo de 2023, 117 comentarios
    Lotus 1-2-3 For Linux - https://news.ycombinator.com/item?id=31455968 - mayo de 2022, 83 comentarios
    Lotus 1-2-3 arbitrary resolution - https://news.ycombinator.com/item?id=26316637 - marzo de 2021, 123 comentarios

  • Había olvidado por completo 1-2-3, pese a haberlo usado brevemente el año pasado.
    El binario 123 todavía funciona bien en Linux, y que un software desaparecido hace tanto simplemente funcione es un logro bastante notable.

  • Siempre quise algo así. Como no uso muchas fuentes ni gráficos en las hojas de cálculo, una hoja de cálculo basada en terminal me queda perfecta.
    Me alegra que por fin exista, y ojalá la porten también a Mac y Windows.

    • En el mismo sitio web también hay reseñas de varios programas de hojas de cálculo para terminal en Linux.
      https://lock.cmpxchg8b.com/spreadsheet.html
    • Emacs tiene desde hace mucho un modo de hoja de cálculo llamado SimpleEmacsSpreadsheet.
      Nunca lo probé, pero vale la pena revisarlo.
      Además, Org-Mode de Emacs es una herramienta que se puede explorar infinitamente, y también hay formas de usar las celdas de tablas de org-mode como una hoja de cálculo junto con la función Calc de Emacs.
      https://www.youtube.com/watch?v=15aDIvb5LJs
      Parece bastante potente y, como es de esperarse en Emacs, puede ejecutarse tanto en terminal como en entorno de ventanas.
    • Ya existe sc: https://www.unix.com/man-page/linux/1/sc/