///|
/// The TLS directory (slot 9).
///
/// TLS callbacks run *before* the entry point, which makes them a classic place
/// to hide anti-debugging or unpacking code. Counting them is the useful part;
/// the addresses themselves are reported through the section map.
///|
pub(all) struct TlsInfo {
callbacks : Int32
zero_fill_size : Int32
raw_data_size : Int32
} derive(@debug.Debug)
///|
/// Read the TLS directory, or `None` when the image has none.
pub fn Pe::tls(self : Pe) -> TlsInfo? raise PeError {
let directory = match self.directory(9) {
None => return None
Some(directory) => directory
}
if directory.virtual_address == 0 || directory.size == 0 {
return None
}
let reader = match self.reader_at_rva(directory.virtual_address) {
Some(reader) => reader
None =>
raise PeError::Malformed(
"TLS directory RVA " +
hex(directory.virtual_address) +
" is not backed by file bytes",
0,
)
}
let wide = self.bits() == 64
// Addresses are virtual addresses and can exceed 32 bits, so they are read
// and rebased in Int64 before anything is narrowed.
let start_address = if wide { reader.u64() } else { reader.u32().to_int64() }
let end_address = if wide { reader.u64() } else { reader.u32().to_int64() }
let _index_address = if wide { reader.u64() } else { reader.u32().to_int64() }
let callbacks_address = if wide {
reader.u64()
} else {
reader.u32().to_int64()
}
let zero_fill_size = reader.u32()
reader.skip(4)
let size = if end_address > start_address {
end_address - start_address
} else {
0L
}
let raw_data_size = if size > 2147483647L {
2147483647
} else {
size.to_int()
}
let base = self.optional.image_base
let mut callbacks = 0
if callbacks_address > base {
let delta = callbacks_address - base
if delta <= 2147483647L {
match self.reader_at_rva(delta.to_int()) {
Some(table) => {
let mut done = false
while !done && callbacks < 4096 {
let entry = if wide { table.u64() } else { table.u32().to_int64() }
if entry == 0L {
done = true
} else {
callbacks = callbacks + 1
}
}
}
None => ()
}
}
}
Some({ callbacks, zero_fill_size, raw_data_size, })
}