https://gcc.gnu.org/g:59079fa643f9fa6ac3c9fddc458d242c1fc96a3e
commit r16-7610-g59079fa643f9fa6ac3c9fddc458d242c1fc96a3e Author: Jose E. Marchesi <[email protected]> Date: Wed Feb 18 12:11:07 2026 +0100 a68: support for importing exports data from archives The compiler tries to find exports data for accessed modules by trying, in order: * Standalone files: FOO.m68 * Shared object: libFOO.so * Archives: libFOO.a * Object files: FOO.o This commit adds support for archives. Most of the code is copied from the go FrontEnd's gcc/go/import-archive.c. Signed-off-by: Jose E. Marchesi <[email protected]> gcc/algol68/ChangeLog * a68-imports.cc (a68_find_export_data): Make visible externally. (a68_find_export_data): Try reading export data from an archive file. * a68.h: Adjust prototype of a68_find_export_data accordingly. * a68-imports-archive.cc: New file. * Make-lang.in (ALGOL68_OBJS): Build algol/a68-imports-archive.o. Diff: --- gcc/algol68/Make-lang.in | 1 + gcc/algol68/a68-imports-archive.cc | 885 +++++++++++++++++++++++++++++++++++++ gcc/algol68/a68-imports.cc | 27 +- gcc/algol68/a68.h | 7 + 4 files changed, 914 insertions(+), 6 deletions(-) diff --git a/gcc/algol68/Make-lang.in b/gcc/algol68/Make-lang.in index 392818b6cb7a..3a0f51b06a75 100644 --- a/gcc/algol68/Make-lang.in +++ b/gcc/algol68/Make-lang.in @@ -67,6 +67,7 @@ ALGOL68_OBJS = algol68/a68-lang.o \ algol68/a68-diagnostics.o \ algol68/a68-exports.o \ algol68/a68-imports.o \ + algol68/a68-imports-archive.o \ algol68/a68-parser.o \ algol68/a68-parser-keywords.o \ algol68/a68-parser-bottom-up.o \ diff --git a/gcc/algol68/a68-imports-archive.cc b/gcc/algol68/a68-imports-archive.cc new file mode 100644 index 000000000000..ee504bc2110a --- /dev/null +++ b/gcc/algol68/a68-imports-archive.cc @@ -0,0 +1,885 @@ +/* Handling of module export data in library archives. + This code has bee adapted from the Go front-end. + + Copyright (C) 2009 The Go Authors. + Copyright (C) 2026 Jose E. Marchesi. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + GCC is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING3. If not see + <http://www.gnu.org/licenses/>. */ + +#define INCLUDE_MEMORY +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "vec.h" + +#include <map> +#include <string> + +#include "a68.h" + + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +// Archive magic numbers. + +static const char armag[] = +{ + '!', '<', 'a', 'r', 'c', 'h', '>', '\n' +}; + +static const char armagt[] = +{ + '!', '<', 't', 'h', 'i', 'n', '>', '\n' +}; + +static const char armagb[] = +{ + '<', 'b', 'i', 'g', 'a', 'f', '>', '\n' +}; + +static const char arfmag[2] = { '`', '\n' }; + +// Archive fixed length header for AIX big format. + +struct Archive_fl_header +{ + // Archive magic string. + char fl_magic[8]; + // Offset to member table. + char fl_memoff[20]; + // Offset to global symbol table. + char fl_gstoff[20]; + // Offset to global symbol table for 64-bit objects. + char fl_gst64off[20]; + // Offset to first archive member. + char fl_fstmoff[20]; + // Offset to last archive member. + char fl_lstmoff[20]; + // Offset to first member on free list. + char fl_freeoff[20]; +}; + +// The header of an entry in an archive. This is all readable text, +// padded with spaces where necesary. + +struct Archive_header +{ + // The entry name. + char ar_name[16]; + // The file modification time. + char ar_date[12]; + // The user's UID in decimal. + char ar_uid[6]; + // The user's GID in decimal. + char ar_gid[6]; + // The file mode in octal. + char ar_mode[8]; + // The file size in decimal. + char ar_size[10]; + // The final magic code. + char ar_fmag[2]; +}; + +// The header of an entry in an AIX big archive. +// This is followed by ar_namlen bytes + 2 bytes for arfmag. + +struct Archive_big_header +{ + // The file size in decimal. + char ar_size[20]; + // The next member offset in decimal. + char ar_nxtmem[20]; + // The previous member offset in decimal. + char ar_prvmem[20]; + // The file modification time in decimal. + char ar_date[12]; + // The user's UID in decimal. + char ar_uid[12]; + // The user's GID in decimal. + char ar_gid[12]; + // The file mode in octal. + char ar_mode[12]; + // The file name length in decimal. + char ar_namlen[4]; +}; + +// The functions in this file extract Go export data from an archive. + +static const int archive_magic_len = 8; + +// return true if bytes, which are from the start of the file, are an +// archive magic number. + +bool +a68_is_archive_magic(const char* bytes) +{ + return (memcmp(bytes, armag, archive_magic_len) == 0 + || memcmp(bytes, armagt, archive_magic_len) == 0 + || memcmp(bytes, armagb, archive_magic_len) == 0); +} + +// An object used to read an archive file. + +class Archive_file +{ + public: + Archive_file(const std::string& filename, int fd, location_t location) + : filename_(filename), fd_(fd), filesize_(-1), first_member_offset_(0), + extended_names_(), is_thin_archive_(false), is_big_archive_(false), + location_(location), nested_archives_() + { } + + // Initialize. + bool + initialize(); + + // Return the file name. + const std::string& + filename() const + { return this->filename_; } + + // Get the file size. + off_t + filesize() const + { return this->filesize_; } + + // Return the offset of the first member. + off_t + first_member_offset() const + { return this->first_member_offset_; } + + // Return whether this is a thin archive. + bool + is_thin_archive() const + { return this->is_thin_archive_; } + + // Return whether this is a big archive. + bool + is_big_archive() const + { return this->is_big_archive_; } + + // Return the location of the import statement. + location_t + location() const + { return this->location_; } + + // Read bytes. + bool + read(off_t offset, off_t size, char*); + + // Parse a decimal in readable text. + bool + parse_decimal(const char* str, off_t size, long* res) const; + + // Read the archive header at OFF, setting *PNAME, *SIZE, + // *NESTED_OFF and *NEXT_OFF. + bool + read_header(off_t off, std::string* pname, off_t* size, off_t* nested_off, + off_t* next_off); + + // Interpret the header of HDR, the header of the archive member at + // file offset OFF. Return whether it succeeded. Set *SIZE to the + // size of the member. Set *PNAME to the name of the member. Set + // *NESTED_OFF to the offset in a nested archive. + bool + interpret_header(const Archive_header* hdr, off_t off, + std::string* pname, off_t* size, off_t* nested_off) const; + + // Get the file and offset for an archive member. + bool + get_file_and_offset(off_t off, const std::string& hdrname, + off_t nested_off, int* memfd, off_t* memoff, + std::string* memname); + + private: + // Initialize a big archive (AIX) + bool + initialize_big_archive(); + + // Initialize a normal archive + bool + initialize_archive(); + + // Read the big archive header at OFF, setting *PNAME, *SIZE and *NEXT_OFF. + bool + read_big_archive_header(off_t off, std::string* pname, + off_t* size, off_t* next_off); + + // Read the normal archive header at OFF, setting *PNAME, *SIZE, + // *NESTED_OFF and *NEXT_OFF. + bool + read_archive_header(off_t off, std::string* pname, off_t* size, + off_t* nested_off, off_t* next_off); + + // For keeping track of open nested archives in a thin archive file. + typedef std::map<std::string, Archive_file*> Nested_archive_table; + + // The name of the file. + std::string filename_; + // The file descriptor. + int fd_; + // The file size; + off_t filesize_; + // The first member offset; + off_t first_member_offset_; + // The extended name table. + std::string extended_names_; + // Whether this is a thin archive. + bool is_thin_archive_; + // Whether this is a big archive. + bool is_big_archive_; + // The location of the import statements. + location_t location_; + // Table of nested archives. + Nested_archive_table nested_archives_; +}; + +bool +Archive_file::initialize() +{ + struct stat st; + if (fstat(this->fd_, &st) < 0) + { + a68_error (NO_NODE, "Z: doing stat", this->filename_.c_str()); + return false; + } + this->filesize_ = st.st_size; + + char buf[sizeof(armagt)]; + if (::lseek(this->fd_, 0, SEEK_SET) < 0 + || ::read(this->fd_, buf, sizeof(armagt)) != sizeof(armagt)) + { + a68_error (NO_NODE, "Z: reading from archive", this->filename_.c_str()); + return false; + } + if (memcmp(buf, armagt, sizeof(armagt)) == 0) + this->is_thin_archive_ = true; + else if (memcmp(buf, armagb, sizeof(armagb)) == 0) + this->is_big_archive_ = true; + + if (this->is_big_archive_) + return this->initialize_big_archive(); + else + return this->initialize_archive(); +} + +// Initialize a big archive (AIX). + +bool +Archive_file::initialize_big_archive() +{ + Archive_fl_header flhdr; + + // Read the fixed length header. + if (::lseek(this->fd_, 0, SEEK_SET) < 0 + || ::read(this->fd_, &flhdr, sizeof(flhdr)) != sizeof(flhdr)) + { + a68_error (NO_NODE, "Z: could not read archive header", + this->filename_.c_str()); + return false; + } + + // Parse offset of the first member. + long off; + if (!this->parse_decimal(flhdr.fl_fstmoff, sizeof(flhdr.fl_fstmoff), &off)) + { + char* buf = new char[sizeof(flhdr.fl_fstmoff) + 1]; + memcpy(buf, flhdr.fl_fstmoff, sizeof(flhdr.fl_fstmoff)); + a68_error (NO_NODE, + ("Z: malformed first member offset in archive header" + " (expected decimal, got Z)"), + this->filename_.c_str(), buf); + delete[] buf; + return false; + } + if (off == 0) // Empty archive. + this->first_member_offset_ = this->filesize_; + else + this->first_member_offset_ = off; + return true; +} + +// Initialize a normal archive. + +bool +Archive_file::initialize_archive() +{ + this->first_member_offset_ = sizeof(armag); + if (this->first_member_offset_ == this->filesize_) + { + // Empty archive. + return true; + } + + // Look for the extended name table. + std::string filename; + off_t size; + off_t next_off; + if (!this->read_header(this->first_member_offset_, &filename, + &size, NULL, &next_off)) + return false; + if (filename.empty()) + { + // We found the symbol table. + if (!this->read_header(next_off, &filename, &size, NULL, NULL)) + filename.clear(); + } + if (filename == "/") + { + char* rdbuf = new char[size]; + if (::read(this->fd_, rdbuf, size) != size) + { + a68_error (NO_NODE, "Z: could not read extended names", + filename.c_str()); + delete[] rdbuf; + return false; + } + this->extended_names_.assign(rdbuf, size); + delete[] rdbuf; + } + + return true; +} + +// Read bytes from the file. + +bool +Archive_file::read(off_t offset, off_t size, char* buf) +{ + if (::lseek(this->fd_, offset, SEEK_SET) < 0 + || ::read(this->fd_, buf, size) != size) + { + a68_error (NO_NODE, "Z: reading from archive", this->filename_.c_str()); + return false; + } + return true; +} + +// Parse a decimal in readable text. + +bool +Archive_file::parse_decimal(const char* str, off_t size, long* res) const +{ + char* buf = new char[size + 1]; + memcpy(buf, str, size); + char* ps = buf + size; + while (ps > buf && ps[-1] == ' ') + --ps; + *ps = '\0'; + + errno = 0; + char* end; + *res = strtol(buf, &end, 10); + if (*end != '\0' + || *res < 0 + || (*res == LONG_MAX && errno == ERANGE)) + { + delete[] buf; + return false; + } + delete[] buf; + return true; +} + +// Read the header at OFF. Set *PNAME to the name, *SIZE to the size, +// *NESTED_OFF to the nested offset, and *NEXT_OFF to the next member offset. + +bool +Archive_file::read_header(off_t off, std::string* pname, off_t* size, + off_t* nested_off, off_t* next_off) +{ + if (::lseek(this->fd_, off, SEEK_SET) < 0) + { + a68_error (NO_NODE, "Z: seeking in archive", this->filename_.c_str()); + return false; + } + if (this->is_big_archive_) + return this->read_big_archive_header(off, pname, size, next_off); + else + return this->read_archive_header(off, pname, size, nested_off, next_off); +} + +// Read the big archive header at OFF, setting *PNAME, *SIZE and *NEXT_OFF. + +bool +Archive_file::read_big_archive_header(off_t off, std::string* pname, + off_t* size, off_t* next_off) +{ + Archive_big_header hdr; + ssize_t got; + + got = ::read(this->fd_, &hdr, sizeof hdr); + if (got != sizeof hdr) + { + if (got < 0) + a68_error (NO_NODE, "Z: reading from archive", this->filename_.c_str()); + else if (got > 0) + a68_error (NO_NODE, "Z short entry header at L", + this->filename_.c_str(), static_cast<long>(off)); + else + a68_error (NO_NODE, "Z: unexpected EOF at L", + this->filename_.c_str(), static_cast<long>(off)); + } + + long local_size; + if (!this->parse_decimal(hdr.ar_size, sizeof(hdr.ar_size), &local_size)) + { + char* buf = new char[sizeof(hdr.ar_size) + 1]; + memcpy(buf, hdr.ar_size, sizeof(hdr.ar_size)); + a68_error (NO_NODE, + ("Z: malformed size in entry header at L" + " (expected decimal, got %s)"), + this->filename_.c_str(), static_cast<long>(off), buf); + delete[] buf; + return false; + } + *size = local_size; + + long namlen; + if (!this->parse_decimal(hdr.ar_namlen, sizeof(hdr.ar_namlen), &namlen)) + { + char* buf = new char[sizeof(hdr.ar_namlen) + 1]; + memcpy(buf, hdr.ar_namlen, sizeof(hdr.ar_namlen)); + a68_error (NO_NODE, + ("Z: malformed name length in entry header at L" + " (expected decimal, got %s)"), + this->filename_.c_str(), static_cast<long>(off), buf); + delete[] buf; + return false; + } + // Read member name following member header. + char* rdbuf = new char[namlen]; + got = ::read(this->fd_, rdbuf, namlen); + if (got != namlen) + { + a68_error (NO_NODE, + "Z: malformed member name in entry header at L", + this->filename_.c_str(), static_cast<long>(off)); + delete[] rdbuf; + return false; + } + pname->assign(rdbuf, namlen); + delete[] rdbuf; + + long local_next_off; + if (!this->parse_decimal(hdr.ar_nxtmem, sizeof(hdr.ar_nxtmem), &local_next_off)) + { + char* buf = new char[sizeof(hdr.ar_nxtmem) + 1]; + memcpy(buf, hdr.ar_nxtmem, sizeof(hdr.ar_nxtmem)); + a68_error (NO_NODE, + ("Z: malformed next member offset in entry header at L" + " (expected decimal, got %s)"), + this->filename_.c_str(), static_cast<long>(off), buf); + delete[] buf; + return false; + } + if (next_off != NULL) + { + if (local_next_off == 0) // Last member. + *next_off = this->filesize_; + else + *next_off = local_next_off; + } + return true; +} + +// Read the normal archive header at OFF, setting *PNAME, *SIZE, +// *NESTED_OFF and *NEXT_OFF. + +bool +Archive_file::read_archive_header(off_t off, std::string* pname, off_t* size, + off_t* nested_off, off_t* next_off) +{ + Archive_header hdr; + ssize_t got = ::read(this->fd_, &hdr, sizeof hdr); + if (got != sizeof hdr) + { + if (got < 0) + a68_error (NO_NODE, "Z: reading from archive", this->filename_.c_str()); + else if (got > 0) + a68_error (NO_NODE, "Z: short archive header at L", + this->filename_.c_str(), static_cast<long>(off)); + else + a68_error (NO_NODE, "Z: unexpected EOF at L", + this->filename_.c_str(), static_cast<long>(off)); + } + off_t local_nested_off; + if (!this->interpret_header(&hdr, off, pname, size, &local_nested_off)) + return false; + if (nested_off != NULL) + *nested_off = local_nested_off; + + off_t local_next_off; + local_next_off = off + sizeof(Archive_header); + if (!this->is_thin_archive_ || pname->empty() || *pname == "/") + local_next_off += *size; + if ((local_next_off & 1) != 0) + ++local_next_off; + if (local_next_off > this->filesize_) // Last member. + local_next_off = this->filesize_; + if (next_off != NULL) + *next_off = local_next_off; + return true; +} + +// Interpret the header of HDR, the header of the archive member at +// file offset OFF. + +bool +Archive_file::interpret_header(const Archive_header* hdr, off_t off, + std::string* pname, off_t* size, + off_t* nested_off) const +{ + if (memcmp(hdr->ar_fmag, arfmag, sizeof arfmag) != 0) + { + a68_error (NO_NODE, "Z: malformed archive header at L", + this->filename_.c_str(), static_cast<unsigned long>(off)); + return false; + } + + long local_size; + if (!this->parse_decimal(hdr->ar_size, sizeof hdr->ar_size, &local_size)) + { + a68_error (NO_NODE, "Z: malformed archive header size at L", + this->filename_.c_str(), static_cast<unsigned long>(off)); + return false; + } + *size = local_size; + + *nested_off = 0; + if (hdr->ar_name[0] != '/') + { + const char* name_end = strchr(hdr->ar_name, '/'); + if (name_end == NULL + || name_end - hdr->ar_name >= static_cast<int>(sizeof hdr->ar_name)) + { + a68_error (NO_NODE, + "Z: malformed archive header name at L", + this->filename_.c_str(), static_cast<unsigned long>(off)); + return false; + } + pname->assign(hdr->ar_name, name_end - hdr->ar_name); + } + else if (hdr->ar_name[1] == ' ') + { + // This is the symbol table. + pname->clear(); + } + else if (hdr->ar_name[1] == 'S' && hdr->ar_name[2] == 'Y' + && hdr->ar_name[3] == 'M' && hdr->ar_name[4] == '6' + && hdr->ar_name[5] == '4' && hdr->ar_name[6] == '/' + && hdr->ar_name[7] == ' ' + ) + { + // 64-bit symbol table. + pname->clear(); + } + else if (hdr->ar_name[1] == '/') + { + // This is the extended name table. + pname->assign(1, '/'); + } + else + { + char* end; + errno = 0; + long x = strtol(hdr->ar_name + 1, &end, 10); + long y = 0; + if (*end == ':') + y = strtol(end + 1, &end, 10); + if (*end != ' ' + || x < 0 + || (x == LONG_MAX && errno == ERANGE) + || static_cast<size_t>(x) >= this->extended_names_.size()) + { + a68_error (NO_NODE, "Z: bad extended name index at L", + this->filename_.c_str(), static_cast<unsigned long>(off)); + return false; + } + + const char* name = this->extended_names_.data() + x; + const char* name_end = strchr(name, '\n'); + if (static_cast<size_t>(name_end - name) > this->extended_names_.size() + || name_end[-1] != '/') + { + a68_error (NO_NODE, + "Z: bad extended name entry at header L", + this->filename_.c_str(), static_cast<unsigned long>(off)); + return false; + } + pname->assign(name, name_end - 1 - name); + *nested_off = y; + } + + return true; +} + +// Get the file and offset for an archive member. + +bool +Archive_file::get_file_and_offset(off_t off, const std::string& hdrname, + off_t nested_off, int* memfd, off_t* memoff, + std::string* memname) +{ + if (this->is_big_archive_) + { + *memfd = this->fd_; + *memoff = (off + sizeof(Archive_big_header) + hdrname.length() + + sizeof(arfmag)); + if ((*memoff & 1) != 0) + ++*memoff; + *memname = this->filename_ + '(' + hdrname + ')'; + return true; + } + else if (!this->is_thin_archive_) + { + *memfd = this->fd_; + *memoff = off + sizeof(Archive_header); + *memname = this->filename_ + '(' + hdrname + ')'; + return true; + } + + std::string filename = hdrname; + if (!IS_ABSOLUTE_PATH(filename.c_str())) + { + const char* archive_path = this->filename_.c_str(); + const char* basename = lbasename(archive_path); + if (basename > archive_path) + filename.replace(0, 0, + this->filename_.substr(0, basename - archive_path)); + } + + if (nested_off > 0) + { + // This is a member of a nested archive. + Archive_file* nfile; + Nested_archive_table::const_iterator p = + this->nested_archives_.find(filename); + if (p != this->nested_archives_.end()) + nfile = p->second; + else + { + int nfd = open(filename.c_str(), O_RDONLY | O_BINARY); + if (nfd < 0) + { + a68_error (NO_NODE, "Z: cannot open nested archive Z", + this->filename_.c_str(), filename.c_str()); + return false; + } + nfile = new Archive_file(filename, nfd, this->location_); + if (!nfile->initialize()) + { + delete nfile; + return false; + } + this->nested_archives_[filename] = nfile; + } + + std::string nname; + off_t nsize; + off_t nnested_off; + if (!nfile->read_header(nested_off, &nname, &nsize, &nnested_off, NULL)) + return false; + return nfile->get_file_and_offset(nested_off, nname, nnested_off, + memfd, memoff, memname); + } + + // An external member of a thin archive. + *memfd = open(filename.c_str(), O_RDONLY | O_BINARY); + if (*memfd < 0) + { + a68_error (NO_NODE, "Z: opening archive", filename.c_str()); + return false; + } + *memoff = 0; + *memname = filename; + return true; +} + +// An archive member iterator. This is more-or-less copied from gold. + +class Archive_iterator +{ + public: + // The header of an archive member. This is what this iterator + // points to. + struct Header + { + // The name of the member. + std::string name; + // The file offset of the member. + off_t off; + // The file offset of a nested archive member. + off_t nested_off; + // The size of the member. + off_t size; + }; + + Archive_iterator(Archive_file* afile, off_t off) + : afile_(afile), off_(off) + { this->read_next_header(); } + + const Header& + operator*() const + { return this->header_; } + + const Header* + operator->() const + { return &this->header_; } + + Archive_iterator& + operator++() + { + if (this->off_ == this->afile_->filesize()) + return *this; + this->off_ = this->next_off_; + this->read_next_header(); + return *this; + } + + Archive_iterator + operator++(int) + { + Archive_iterator ret = *this; + ++*this; + return ret; + } + + bool + operator==(const Archive_iterator& p) const + { return this->off_ == p->off; } + + bool + operator!=(const Archive_iterator& p) const + { return this->off_ != p->off; } + + private: + void + read_next_header(); + + // The underlying archive file. + Archive_file* afile_; + // The current offset in the file. + off_t off_; + // The offset of the next member. + off_t next_off_; + // The current archive header. + Header header_; +}; + +// Read the next archive header. + +void +Archive_iterator::read_next_header() +{ + off_t filesize = this->afile_->filesize(); + while (true) + { + if (this->off_ == filesize) + { + this->header_.off = filesize; + return; + } + + if (!this->afile_->read_header(this->off_, &this->header_.name, + &this->header_.size, + &this->header_.nested_off, + &this->next_off_)) + { + this->header_.off = filesize; + this->off_ = filesize; + return; + } + this->header_.off = this->off_; + + // Skip special members. + if (!this->header_.name.empty() && this->header_.name != "/") + return; + + this->off_ = this->next_off_; + } +} + +// Initial iterator. + +Archive_iterator +archive_begin(Archive_file* afile) +{ + return Archive_iterator(afile, afile->first_member_offset()); +} + +// Final iterator. + +Archive_iterator +archive_end(Archive_file* afile) +{ + return Archive_iterator(afile, afile->filesize()); +} + +/* Get a68 imports from an archive. We walk through the archive and read + imports from each member. */ + +char * +a68_find_archive_export_data (const char *filename, int fd, + size_t *size) +{ + char *ret = NULL; + size_t ret_size = 0; + + Archive_file afile(filename, fd, UNKNOWN_LOCATION); + if (!afile.initialize()) + return NULL; + + + Archive_iterator pend = archive_end(&afile); + for (Archive_iterator p = archive_begin(&afile); p != pend; p++) + { + int member_fd; + off_t member_off; + std::string member_name; + if (!afile.get_file_and_offset(p->off, p->name, p->nested_off, + &member_fd, &member_off, &member_name)) + { + *size = 0; + return NULL; + } + + size_t exports_size; + char *exports = a68_find_object_export_data (member_name, + member_fd, + member_off, + &exports_size); + if (exports != NULL) + { + if (ret == NULL) + { + ret = exports; + ret_size = exports_size; + } + else + { + ret = (char *) xrealloc (ret, ret_size + exports_size); + memcpy (ret + ret_size, exports, exports_size); + ret_size += exports_size; + free (exports); + } + } + } + + *size = ret_size; + return ret; +} diff --git a/gcc/algol68/a68-imports.cc b/gcc/algol68/a68-imports.cc index 021417b5bee8..fe95ae355475 100644 --- a/gcc/algol68/a68-imports.cc +++ b/gcc/algol68/a68-imports.cc @@ -231,9 +231,9 @@ a68_read_export_data (int fd, uint64_t offset, char **pbuf, size_t *plen, /* Look for export data in an object file. */ -static char * +char * a68_find_object_export_data (const std::string& filename, - int fd, uint64_t offset, size_t *psize) + int fd, off_t offset, size_t *psize) { char *buf; size_t len; @@ -324,11 +324,26 @@ a68_find_export_data (const std::string &filename, int fd, size_t *psize) return buf; } -#if 0 /* See if we can read this as an archive. */ - if (Import::is_archive_magic(buf)) - return Import::find_archive_export_data(filename, fd, location); -#endif + { + char buf[8]; + + if (lseek (fd, 0, SEEK_SET) < 0) + { + a68_error (NO_NODE, "lseek Z failed", filename.c_str ()); + return NULL; + } + + c = read (fd, buf, 8); + if (c < 8) + { + a68_error (NO_NODE, "read Z failed", filename.c_str ()); + return NULL; + } + + if (a68_is_archive_magic (buf)) + return a68_find_archive_export_data(filename.c_str (), fd, psize); + } return NULL; } diff --git a/gcc/algol68/a68.h b/gcc/algol68/a68.h index 17c419a6881e..cf195f213e10 100644 --- a/gcc/algol68/a68.h +++ b/gcc/algol68/a68.h @@ -1128,6 +1128,13 @@ void a68_do_exports (NODE_T *p); MOIF_T *a68_open_packet (const char *module); bool a68_process_module_map (const char *map, const char **errmsg); +char *a68_find_object_export_data (const std::string &filename, + int fd, off_t offset, size_t *size); + +/* a68-imports-archive.cc */ + +bool a68_is_archive_magic (const char *bytes); +char *a68_find_archive_export_data (const char *filename, int fd, size_t *size); /* a68-parser-debug.cc */
