From e3c5d5859244e01fabd61998ac9387a675fa6345 Mon Sep 17 00:00:00 2001 From: Andrew Barchuk Date: Fri, 12 Jul 2019 08:59:01 +0200 Subject: [PATCH 1/3] Fix parsing of Windows library archives Use Windows-specific symbol index to replace SysV index if present Fixes #173 and #133 --- src/archive/mod.rs | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/src/archive/mod.rs b/src/archive/mod.rs index d9f8b951e..406e06e97 100644 --- a/src/archive/mod.rs +++ b/src/archive/mod.rs @@ -279,6 +279,37 @@ impl<'a> Index<'a> { strtab: strings, }) } + + // Parses Windows Second Linker Member: + // number of members (m): 4 + // member offsets: 4 * m + // number of symbols (n): 4 + // symbol member indexes: 2 * n + // followed by SysV-style string table + // https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#first-linker-member + pub fn parse_windows_linker_member(buffer: &'a [u8]) -> Result { + let offset = &mut 0; + let members = buffer.gread_with::(offset, scroll::LE)? as usize; + let mut member_offsets = Vec::with_capacity(members); + for _ in 0..members { + member_offsets.push(buffer.gread_with::(offset, scroll::LE)?); + } + let symbols = buffer.gread_with::(offset, scroll::LE)? as usize; + let mut symbol_indexes = Vec::with_capacity(symbols); + for _ in 0..symbols { + symbol_indexes.push(buffer.gread_with::(offset, scroll::LE)? as usize); + } + let mut symbol_offsets = Vec::with_capacity(symbols); + for i in symbol_indexes { + symbol_offsets.push(member_offsets[i - 1]); + } + let strtab = strtab::Strtab::parse(buffer, *offset, buffer.len() - *offset, 0x0)?; + Ok(Index { + size: symbols, + symbol_indexes: symbol_offsets, + strtab: strtab.to_vec()?, + }) + } } /// Member names greater than 16 bytes are indirectly referenced using a `/ Archive<'a> { let mut member_array = Vec::new(); let mut index = Index::default(); let mut sysv_name_index = NameIndex::default(); + let mut sysv_symbol_index_seen = false; while *offset < buffer.len() { // realign the cursor to a word boundary, if it's not on one already if *offset & 1 == 1 { @@ -366,7 +398,13 @@ impl<'a> Archive<'a> { let name = member.raw_name(); if name == INDEX_NAME { let data: &[u8] = buffer.pread_with(member.offset as usize, member.size())?; - index = Index::parse_sysv_index(data)?; + index = if sysv_symbol_index_seen { + // Second symbol index is Microsoft's extension of SysV format + Index::parse_windows_linker_member(data)? + } else { + sysv_symbol_index_seen = true; + Index::parse_sysv_index(data)? + } } else if member.bsd_name == Some(BSD_SYMDEF_NAME) || member.bsd_name == Some(BSD_SYMDEF_SORTED_NAME) { let data: &[u8] = buffer.pread_with(member.offset as usize, member.size())?; From a95d0ac6f9bbe5e5a6f40258dfbb64d98823221c Mon Sep 17 00:00:00 2001 From: Andrew Barchuk Date: Fri, 12 Jul 2019 09:07:07 +0200 Subject: [PATCH 2/3] Fix parsing of aligned archives Archive data sections are 2 byte aligned. Fix the parsing termination condition which was going out of bounds otherwise. --- src/archive/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/archive/mod.rs b/src/archive/mod.rs index 406e06e97..7a96e8e51 100644 --- a/src/archive/mod.rs +++ b/src/archive/mod.rs @@ -384,7 +384,7 @@ impl<'a> Archive<'a> { let mut index = Index::default(); let mut sysv_name_index = NameIndex::default(); let mut sysv_symbol_index_seen = false; - while *offset < buffer.len() { + while *offset + 1 < buffer.len() { // realign the cursor to a word boundary, if it's not on one already if *offset & 1 == 1 { *offset += 1; From 3234094fd7996cf7b7a78d789166ce1a2dde3d26 Mon Sep 17 00:00:00 2001 From: Andrew Barchuk Date: Fri, 12 Jul 2019 10:35:23 +0200 Subject: [PATCH 3/3] Simplify windows linker archive member parsing --- src/archive/mod.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/archive/mod.rs b/src/archive/mod.rs index 7a96e8e51..0d53baabd 100644 --- a/src/archive/mod.rs +++ b/src/archive/mod.rs @@ -295,13 +295,9 @@ impl<'a> Index<'a> { member_offsets.push(buffer.gread_with::(offset, scroll::LE)?); } let symbols = buffer.gread_with::(offset, scroll::LE)? as usize; - let mut symbol_indexes = Vec::with_capacity(symbols); - for _ in 0..symbols { - symbol_indexes.push(buffer.gread_with::(offset, scroll::LE)? as usize); - } let mut symbol_offsets = Vec::with_capacity(symbols); - for i in symbol_indexes { - symbol_offsets.push(member_offsets[i - 1]); + for _ in 0..symbols { + symbol_offsets.push(member_offsets[buffer.gread_with::(offset, scroll::LE)? as usize - 1]); } let strtab = strtab::Strtab::parse(buffer, *offset, buffer.len() - *offset, 0x0)?; Ok(Index { @@ -404,7 +400,7 @@ impl<'a> Archive<'a> { } else { sysv_symbol_index_seen = true; Index::parse_sysv_index(data)? - } + }; } else if member.bsd_name == Some(BSD_SYMDEF_NAME) || member.bsd_name == Some(BSD_SYMDEF_SORTED_NAME) { let data: &[u8] = buffer.pread_with(member.offset as usize, member.size())?;