From aa5ad4ee0e3b677f7a0f7c028e984220d1740047 Mon Sep 17 00:00:00 2001
From: Robert Pengelly <robertapengelly@hotmail.com>
Date: Mon, 7 Apr 2025 23:12:58 +0100
Subject: [PATCH] Read archives
---
ar.h | 19 +++++++++
ld.c | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----
lib.c | 38 ++++++++++++++++++
lib.h | 6 ++-
4 files changed, 180 insertions(+), 9 deletions(-)
create mode 100644 ar.h
diff --git a/ar.h b/ar.h
new file mode 100644
index 0000000..38898a4
--- /dev/null
+++ b/ar.h
@@ -0,0 +1,19 @@
+/******************************************************************************
+ * @file ar.h
+ *****************************************************************************/
+#ifndef _AR_H
+#define _AR_H
+
+struct ar_header {
+
+ char name[16];
+ char mtime[12];
+ char owner[6];
+ char group[6];
+ char mode[8];
+ char size[10];
+ char endsig[2];
+
+};
+
+#endif /* _AR_H */
diff --git a/ld.c b/ld.c
index 59ff6da..3213330 100644
--- a/ld.c
+++ b/ld.c
@@ -6,6 +6,7 @@
#include <string.h>
#include "aout.h"
+#include "ar.h"
#include "elks.h"
#include "ld.h"
#include "lib.h"
@@ -63,6 +64,119 @@ static int read_file_into_memory (const char *filename, unsigned char **memory_p
}
+static void read_object_file (const char *filename, unsigned char *data, unsigned long data_size) {
+
+ if (data[0] == 0x01 && data[1] == 0x03) {
+ read_elks_object (filename, data, data_size);
+ } else if (data[0] == 0x07 && data[1] == 0x01) {
+ read_aout_object (filename, data, data_size);
+ } else {
+ report_at (program_name, 0, REPORT_ERROR, "%s: unrecognised file format", filename);
+ }
+
+}
+
+struct offset_name_table {
+
+ char *name;
+ unsigned long offset;
+
+};
+
+#define ALREADY_READ "Already read"
+
+static void read_archive (const char *filename, unsigned char *data) {
+
+ unsigned char *pos = data + 8;
+ struct ar_header *hdr = (struct ar_header *) pos;
+
+ struct offset_name_table *offset_name_table;
+ char *name, *temp, *string_table_pos;
+
+ unsigned long no_symbols, data_size, i;
+
+ name = xstrndup (hdr->name, sizeof (hdr->name));
+ strip_trailing_spaces (name);
+
+ if (strcmp (name, "/") != 0) {
+
+ report_at (program_name, 0, REPORT_ERROR, "%s: unable to add symbols: archive has no index; run ranlib to add one", filename);
+
+ free (name);
+ return;
+
+ }
+
+ free (name);
+ pos += sizeof (*hdr);
+
+ no_symbols = byte_array_to_integer (pos, 4, 1);
+ pos += 4;
+
+ offset_name_table = xmalloc (sizeof (*offset_name_table) * no_symbols);
+ string_table_pos = (char *) pos + (no_symbols * 4);
+
+ for (i = 0; i < no_symbols; i++) {
+
+ offset_name_table[i].offset = byte_array_to_integer (pos, 4, 1);
+
+ offset_name_table[i].name = (char *) string_table_pos;
+ string_table_pos += strlen (offset_name_table[i].name) + 1;
+
+ }
+
+ while (1) {
+
+ struct symbol *symbol;
+ int change = 0;
+
+ for (i = 0; i < no_symbols; i++) {
+
+ if (!(symbol = symbol_find (offset_name_table[i].name)) || !symbol_is_undefined (symbol)) {
+ continue;
+ }
+
+ pos = data + offset_name_table[i].offset;
+
+ if (memcmp (pos, ALREADY_READ, sizeof (ALREADY_READ)) == 0) {
+ continue;
+ }
+
+ hdr = (struct ar_header *) pos;
+
+ temp = xstrndup (hdr->name, sizeof (hdr->name));
+ strip_trailing_spaces (temp);
+
+ name = xmalloc (strlen (filename) + 1 + strlen (temp) + 1 + 1);
+ sprintf (name, "%s(%s)", filename, temp);
+
+ free (temp);
+
+ temp = xstrndup (hdr->size, sizeof (hdr->size));
+ strip_trailing_spaces (temp);
+
+ data_size = strtoul (temp, NULL, 10);
+ free (temp);
+
+ read_object_file (name, pos + sizeof (*hdr), data_size);
+
+ memcpy (pos, ALREADY_READ, sizeof (ALREADY_READ));
+ free (name);
+
+ change = 1;
+
+ }
+
+ if (change == 0) {
+ break;
+ }
+
+ }
+
+ free (offset_name_table);
+
+}
+
static void read_input_file (const char *filename) {
unsigned char *data;
@@ -75,14 +189,10 @@ static void read_input_file (const char *filename) {
}
- /*if (memcmp (data, "!<arch>\n", 8) == 0) {
- read_archive (filename, data, data_size);
- } else*/ if (data[0] == 0x01 && data[1] == 0x03) {
- read_elks_object (filename, data, data_size);
- } else if (data[0] == 0x07 && data[1] == 0x01) {
- read_aout_object (filename, data, data_size);
+ if (memcmp (data, "!<arch>\n", 8) == 0) {
+ read_archive (filename, data);
} else {
- report_at (program_name, 0, REPORT_ERROR, "%s: unrecognised file format", filename);
+ read_object_file (filename, data, data_size);
}
free (data);
@@ -191,7 +301,7 @@ int main (int argc, char **argv) {
}
- if (fwrite (data, data_size, 1, fp) != 1) {
+ if (data_size > 0 && fwrite (data, data_size, 1, fp) != 1) {
report_at (program_name, 0, REPORT_ERROR, "failed to write data to '%s'", state->output_filename);
}
diff --git a/lib.c b/lib.c
index 0c937d7..a859c31 100644
--- a/lib.c
+++ b/lib.c
@@ -280,6 +280,25 @@ unsigned long array_to_integer (unsigned char *arr, int size) {
}
+unsigned long byte_array_to_integer (unsigned char *arr, int size, int big_endian) {
+
+ if (big_endian) {
+
+ unsigned long value = 0;
+ int i, j;
+
+ for (i = size, j = 0; i > 0; i--, j++) {
+ value |= arr[j] << (CHAR_BIT * (i - 1));
+ }
+
+ return value;
+
+ }
+
+ return array_to_integer (arr, size);
+
+}
+
void integer_to_array (unsigned long value, unsigned char *dest, int size) {
int i;
@@ -299,6 +318,15 @@ char *xstrdup (const char *__p) {
}
+char *xstrndup (const char *__p, unsigned long __size) {
+
+ char *p = xmalloc (__size + 1);
+
+ memcpy (p, __p, __size);
+ return p;
+
+}
+
int xstrcasecmp (const char *__s1, const char *__s2) {
const unsigned char *p1 = (const unsigned char *) __s1;
@@ -464,6 +492,16 @@ void parse_args (int argc, char **argv, int optind) {
}
+void strip_trailing_spaces (char *__p) {
+
+ char *p = __p + strlen (__p);
+
+ while (p > __p && p[-1] == ' ') {
+ *--p = '\0';
+ }
+
+}
+
void *xmalloc (unsigned long __size) {
void *ptr = malloc (__size);
diff --git a/lib.h b/lib.h
index ad1f860..3f545d6 100644
--- a/lib.h
+++ b/lib.h
@@ -17,15 +17,19 @@ struct ld_option {
#define LD_OPTION_HAS_ARG 1
unsigned long array_to_integer (unsigned char *arr, int size);
-void integer_to_array (unsigned long value, unsigned char *dest, int size);
+unsigned long byte_array_to_integer (unsigned char *arr, int size, int big_endian);
int xstrcasecmp (const char *__s1, const char *__s2);
+void integer_to_array (unsigned long value, unsigned char *dest, int size);
int strstart (const char *val, const char **str);
void dynarray_add (void *ptab, long *nb_ptr, void *data);
char *xstrdup (const char *__p);
+char *xstrndup (const char *__p, unsigned long __size);
+
void parse_args (int argc, char **argv, int optind);
+void strip_trailing_spaces (char *__p);
void *xmalloc (unsigned long __size);
void *xrealloc (void *__ptr, unsigned long __size);
--
2.34.1