Inspector de bibliotecas estáticas .a
Un fichero .a es un archivo ar: ocho bytes de firma y, por cada miembro, una cabecera ASCII de anchura fija de 60 bytes —16 de nombre, 12 de fecha de modificación, 6 de uid, 6 de gid, 8 de permisos en octal y 10 de tamaño en decimal— seguida de los bytes del miembro, rellenados hasta un desplazamiento par. Esta herramienta lee todo eso directamente de los bytes y muestra cada miembro con el desplazamiento de su cabecera, el desplazamiento donde empiezan de verdad sus datos, su tamaño, su fecha guardada en UTC, su propietario y sus permisos. Un nombre más largo que el campo de 16 bytes se guarda en otro sitio, y las dos convenciones lo hacen de forma distinta: GNU reúne los nombres largos en un miembro llamado // y escribe /desplazamiento en la cabecera, mientras que BSD y macOS escriben #1/longitud y ponen el nombre en los primeros bytes de los datos del propio miembro, de modo que los datos no empiezan donde acaba la cabecera y el campo de tamaño cuenta también el nombre. Quince caracteres todavía caben como "nombre/", dieciséis ya no; leer mal esa frontera desplaza todos los desplazamientos siguientes, así que la convención se indica de forma explícita y cada miembro dice de dónde salió su nombre. La razón de ser de la herramienta, sin embargo, es el índice de símbolos. El miembro llamado / (o /SYM64/, o __.SYMDEF en BSD) asocia cada símbolo al desplazamiento del miembro que lo define, y no es más que una caché: nada la mantiene al día salvo ranlib. Si el archivo se edita en el sitio, lo ensambla un script o se le añade algo sin reconstruir el índice, este puede apuntar a un miembro que ya no define ese símbolo, o pasar por alto uno que está ahí mismo; y el enlazador, que se fía del índice, informa entonces de una referencia indefinida a un símbolo que el archivo contiene. Por eso se leen los dos lados: el índice y la tabla de símbolos ELF de cada miembro. Las discrepancias se enumeran una a una. Cada miembro ELF muestra además los símbolos globales que define, con la letra de nm, y los que deja indefinidos, que es lo que revela el orden de dependencia entre miembros. Los símbolos con definición fuerte en dos miembros se recogen aparte, porque ese es el "duplicate symbol" con el que falla un enlace; las definiciones débiles, comunes y únicas se repiten legítimamente y no se señalan. Los miembros que no son objetos ELF —un Mach-O o un COFF de otra plataforma, un archivo anidado, un fichero de texto añadido por error— se nombran como tales en lugar de interpretarse a medias, y un archivo fino, cuyos miembros son referencias a ficheros del disco, se identifica como tal porque sus símbolos sencillamente no están dentro. Lo que no puede decirte es qué miembros arrastrará un enlace concreto: eso depende del orden de enlace y de qué queda indefinido al llegar al archivo.
Cómo usar
- Suelta un fichero .a sobre la caja. No se sube nada: el archivo lo lee el JavaScript de la página.
- Mira el resumen para saber la convención (// de GNU o #1/ de BSD), qué clase de índice de símbolos hay y cuántos bytes del fichero son índice y tabla de nombres en lugar de código.
- Revisa primero el panel de índice frente a miembros. Una línea verde significa que la caché y los miembros concuerdan; una roja nombra el símbolo y el miembro que discrepan.
- Recorre la tabla de miembros para ver desplazamientos, tamaños y fechas guardadas: una compilación reproducible escribe fecha, uid y gid a cero, así que cualquier otro valor indica un archivo creado con ar U.
- Abre un miembro en "símbolos por miembro" para ver qué define y qué sigue necesitando, y usa la lista de duplicados para explicar un error de enlace por símbolo duplicado.
Preguntas frecuentes
- ¿Qué significa "archive has no index; run ranlib to add one"?
- Que el archivo se creó sin su tabla de símbolos, normalmente con ar rcS, añadiendo con ar q, o con una herramienta que escribe el formato ar por su cuenta. Sin índice, el enlazador tendría que abrir todos los miembros para saber qué define cada uno, así que la mayoría lo rechaza y pide ranlib, que añade un primer miembro llamado / con el mapa. Ejecutar ranlib sobre el fichero, o ar s, lo arregla en el sitio, y ar rcs lo construye desde el principio. Esta herramienta muestra "índice de símbolos: ninguno" en ese caso, y la lista de miembros se lee igual de bien, porque el índice es un acelerador y no forma parte de los miembros.
- ¿Cómo puede estar mal el índice si ar lo mantiene al día?
- ar reconstruye el índice cada vez que reescribe el archivo, así que los comandos habituales son seguros. El índice se queda obsoleto cuando otra cosa toca el fichero: un script que lo parchea en el sitio, un sistema de compilación que añade con ar q y nunca ejecuta ranlib, un archivo ensamblado a mano o por una herramienta que escribe el formato, o uno copiado entre máquinas y editado. Como el índice guarda un desplazamiento en bytes y no un nombre, un miembro que cambia sin reconstruirlo deja una entrada apuntando a bytes que ya no definen ese símbolo. El enlazador se fía del índice, así que el fallo aparece muy lejos, como una referencia indefinida a un símbolo que se ve perfectamente con nm.
- ¿En qué se diferencian un .a de GNU y uno de BSD, y qué es un archivo fino?
- Solo en cómo guardan los nombres de más de 16 caracteres y el índice de símbolos. GNU pone los nombres largos en un miembro // y los referencia por desplazamiento, y llama al índice / o /SYM64/ en su forma de 64 bits; BSD escribe #1/longitud en el campo del nombre y guarda el nombre en los primeros bytes de los datos del miembro, y llama al índice __.SYMDEF o __.SYMDEF SORTED. Los datos del miembro empiezan, por tanto, en un sitio distinto en cada formato, que es la forma más común de leer mal un archivo. Un archivo fino es una tercera variante, creada por ar T: empieza por !<thin> y guarda solo cabeceras, dejando los datos en los .o originales del disco, de modo que mover solo el .a lo rompe.
- ¿Por qué un miembro lista símbolos indefinidos? ¿Está rota la biblioteca?
- No, es normal y es justo el sentido del listado. Cada miembro es un fichero objeto aparte, y un símbolo indefinido es uno que espera que aporte otro miembro, otra biblioteca o el propio programa. Leerlos juntos revela el orden de dependencia dentro del archivo, algo que importa porque una biblioteca estática se busca, no se fusiona: el enlazador recorre la línea de órdenes una sola vez, arrastra solo los miembros que resuelven algo indefinido en ese momento, y un miembro arrastrado tarde puede dejar indefinido un símbolo que una biblioteca anterior habría aportado. Por eso importa el orden de enlace y por eso existe --start-group.
- ¿Por qué solo algunos símbolos repetidos se marcan como duplicados?
- Porque solo algunos rompen un enlace. Una definición fuerte del mismo nombre en dos miembros es el clásico error de símbolo duplicado: el segundo miembro que arrastre el enlazador choca con el primero. Pero las definiciones débiles (letras W y V de nm), los símbolos comunes (C) y los únicos de GNU (u) están pensados para repetirse: las funciones en línea, las plantillas y las tablas virtuales de C++ se emiten en cada objeto que las usa y el enlazador conserva una copia. Una libstdc++.a real tiene miles de repeticiones así y ningún error, de modo que listarlas todas enterraría la que importa. Aquí solo se recogen los nombres con definición fuerte en más de un miembro.
- ¿Se sube el archivo a algún sitio?
- No. Se lee con la File API del navegador y lo analiza el JavaScript de la página; no hay servidor al que enviarlo. Con una biblioteca estática eso importa más que con otros ficheros, porque un .a de un proveedor o de una compilación interna suele ser algo que no eres libre de subir. Puedes desconectar la red después de cargar la página y la herramienta sigue funcionando; el fichero nunca sale de la pestaña.
Herramientas relacionadas
Inspector de .npy y .npz de NumPy
Lee la cabecera de un .npy o .npz en el navegador: dtype, shape, orden de bytes, campos y una vista de valores, sin NumPy y sin subir nada.
Visor de archivos mbox
Divide un archivo .mbox en tu navegador: límites de mensaje, cabeceras decodificadas, estructura MIME, hilos y Message-ID duplicados. No se sube nada.
Inspector de ZIP
Suelta un ZIP y mira cada archivo dentro — tamaños, contenido y descarga individual — sin desempaquetar localmente.
Inspector de archivos HAR (visor de HTTP Archive)
Suelta un .har de DevTools de Chrome, Firefox o Safari y verás cada solicitud — método, estado, tamaño, tiempo — con tablas de más lentas y grandes.
Validador de archivos de zona DNS
Pega un archivo de zona BIND y descubre lo que dice de verdad: cada nombre completo, el SOA explicado y las trampas que un analizador no señala.
Inspector de pickle de Python
Desensambla un .pkl en el navegador: cada opcode, el memo, el valor que reconstruye y si cargarlo ejecutaría código.