Skip to content

Commit

Permalink
read/archive: handle 64-bit symbol table names (#366)
Browse files Browse the repository at this point in the history
  • Loading branch information
philipc authored Aug 27, 2021
1 parent 5163b28 commit 0f73488
Showing 1 changed file with 67 additions and 2 deletions.
69 changes: 67 additions & 2 deletions src/read/archive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,21 @@ use crate::archive;
use crate::read::{self, Error, ReadError, ReadRef};

/// The kind of archive format.
// TODO: Gnu64 and Darwin64 (and Darwin for writing)
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum ArchiveKind {
/// There are no special files that indicate the archive format.
Unknown,
/// The GNU (or System V) archive format.
Gnu,
/// The GNU (or System V) archive format with 64-bit symbol table.
Gnu64,
/// The BSD archive format.
Bsd,
/// The BSD archive format with 64-bit symbol table.
///
/// This is used for Darwin.
Bsd64,
/// The Windows COFF archive format.
Coff,
}
Expand Down Expand Up @@ -54,14 +59,18 @@ impl<'data, R: ReadRef<'data>> ArchiveFile<'data, R> {

// The first few members may be special, so parse them.
// GNU has:
// - "/": symbol table (optional)
// - "/" or "/SYM64/": symbol table (optional)
// - "//": names table (optional)
// COFF has:
// - "/": first linker member
// - "/": second linker member
// - "//": names table
// BSD has:
// - "__.SYMDEF" or "__.SYMDEF SORTED": symbol table (optional)
// BSD 64-bit has:
// - "__.SYMDEF_64" or "__.SYMDEF_64 SORTED": symbol table (optional)
// BSD may use the extended name for the symbol table. This is handled
// by `ArchiveMember::parse`.
if tail < len {
let member = ArchiveMember::parse(data, &mut tail, &[])?;
if member.name == b"/" {
Expand Down Expand Up @@ -92,6 +101,20 @@ impl<'data, R: ReadRef<'data>> ArchiveFile<'data, R> {
file.offset = tail;
}
}
} else if member.name == b"/SYM64/" {
// GNU 64-bit symbol table.
file.kind = ArchiveKind::Gnu64;
file.symbols = member.file_range();
file.offset = tail;

if tail < len {
let member = ArchiveMember::parse(data, &mut tail, &[])?;
if member.name == b"//" {
// GNU names table.
file.names = member.data(data)?;
file.offset = tail;
}
}
} else if member.name == b"//" {
// GNU names table.
file.kind = ArchiveKind::Gnu;
Expand All @@ -102,6 +125,11 @@ impl<'data, R: ReadRef<'data>> ArchiveFile<'data, R> {
file.kind = ArchiveKind::Bsd;
file.symbols = member.file_range();
file.offset = tail;
} else if member.name == b"__.SYMDEF_64" || member.name == b"__.SYMDEF_64 SORTED" {
// BSD 64-bit symbol table.
file.kind = ArchiveKind::Bsd64;
file.symbols = member.file_range();
file.offset = tail;
} else {
// TODO: This could still be a BSD file. We leave this as unknown for now.
}
Expand Down Expand Up @@ -346,6 +374,22 @@ mod tests {
let archive = ArchiveFile::parse(&data[..]).unwrap();
assert_eq!(archive.kind(), ArchiveKind::Gnu);

let data = b"\
!<arch>\n\
/SYM64/ 4 `\n\
0000";
let archive = ArchiveFile::parse(&data[..]).unwrap();
assert_eq!(archive.kind(), ArchiveKind::Gnu64);

let data = b"\
!<arch>\n\
/SYM64/ 4 `\n\
0000\
// 4 `\n\
0000";
let archive = ArchiveFile::parse(&data[..]).unwrap();
assert_eq!(archive.kind(), ArchiveKind::Gnu64);

let data = b"\
!<arch>\n\
__.SYMDEF 4 `\n\
Expand All @@ -367,6 +411,27 @@ mod tests {
let archive = ArchiveFile::parse(&data[..]).unwrap();
assert_eq!(archive.kind(), ArchiveKind::Bsd);

let data = b"\
!<arch>\n\
__.SYMDEF_64 4 `\n\
0000";
let archive = ArchiveFile::parse(&data[..]).unwrap();
assert_eq!(archive.kind(), ArchiveKind::Bsd64);

let data = b"\
!<arch>\n\
#1/12 16 `\n\
__.SYMDEF_640000";
let archive = ArchiveFile::parse(&data[..]).unwrap();
assert_eq!(archive.kind(), ArchiveKind::Bsd64);

let data = b"\
!<arch>\n\
#1/19 23 `\n\
__.SYMDEF_64 SORTED0000";
let archive = ArchiveFile::parse(&data[..]).unwrap();
assert_eq!(archive.kind(), ArchiveKind::Bsd64);

let data = b"\
!<arch>\n\
/ 4 `\n\
Expand Down

0 comments on commit 0f73488

Please sign in to comment.