Read archives
authorRobert Pengelly <robertapengelly@hotmail.com>
Mon, 7 Apr 2025 22:12:58 +0000 (23:12 +0100)
committerRobert Pengelly <robertapengelly@hotmail.com>
Mon, 7 Apr 2025 22:12:58 +0000 (23:12 +0100)
ar.h [new file with mode: 0644]
ld.c
lib.c
lib.h

diff --git a/ar.h b/ar.h
new file mode 100644 (file)
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 59ff6da4a140c8620026634b01c7f826415a92c4..3213330a4fe9a618c9bd2a1a1fe42037ad9949a2 100644 (file)
--- 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 0c937d7576e0509a7c72a6649ddcae83ea0e8b41..a859c318b2cba0fdd5f051b42cfd01ffac991849 100644 (file)
--- 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 ad1f86002b5c4f11588e1ace3e3df0e34102029f..3f545d6f054fda24799cab5f237cec02cff72044 100644 (file)
--- 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);