-
Notifications
You must be signed in to change notification settings - Fork 163
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Redesign goblin::elf::dynamic::DynamicInfo
to expose the optionality of DT_JMPREL
#344
Comments
Sounds good to me, hopefully it’s straightforward fix? Good to get this stuff right now. Are there any other fields that would have similar semantics? |
The fix for
Yes, there are a lot, as shown in Figure 2-7. Dynamic Array Tags, The following tags are optional in an executable:
The following tags are optional in a shared object:
The following tags may be optional (they are unspecified):
In addition to the optional vs. mandatory nature, there are dependencies between some tags:
Therefore, the following fields in
I may have missed some other tags, and I came into the conclusion that:
I have a question, though: why are we transforming the values of some tags from virtual addresses into file offsets? |
@m4b, the following is an idea about the new impl DynamicTags64 {
pub fn parse() -> Self {}
pub fn tags_iter(&self) -> impl Iterator<Item = (NonZeroU64, u64)> {}
// DT_NEEDED
pub fn needed_libraries_iter(&self) -> impl Iterator<Item = &CStr> {}
// DT_JMPREL, DT_PLTRELSZ, DT_PLTREL
pub fn procedure_linkage_table_relocation_info(&self) -> Option<ProcedureLinkageTableRelocations64> {}
// DT_PLTGOT
pub fn global_offset_table_address(&self) -> Option<u64> {}
// DT_HASH
pub fn symbol_hash_table_address(&self) -> u64 {}
// DT_STRTAB, DT_STRSZ
pub fn string_table_info(&self) -> StringTable64 {}
// DT_SYMTAB, DT_SYMENT
pub fn symbol_table_info(&self) -> SymbolTable64 {}
// DT_RELA, DT_RELASZ, DT_RELAENT
pub fn explicit_relocation_table_info(&self) -> Option<RelocationTable64> {}
// DT_REL, DT_RELSZ, DT_RELENT
pub fn implicit_relocation_table_info(&self) -> Option<RelocationTable64> {}
// DT_INIT
pub fn initialization_function_address(&self) -> Option<u64> {}
// DT_FINI
pub fn termination_function_address(&self) -> Option<u64> {}
// DT_SONAME
pub fn shared_object_name(&self) -> Option<&CStr> {}
// DT_RPATH, DT_RUNPATH
pub fn library_search_path_info(&self) -> LibrarySearchPaths {}
// DT_SYMBOLIC
pub fn local_symbol_resolution_starts_from_shared_object(&self) -> bool {}
// DT_DEBUG
pub fn debug_value(&self) -> Option<u64> {}
// DT_TEXTREL
pub fn relocations_can_modify_read_only_segments(&self) -> bool {}
// DT_BIND_NOW
pub fn process_all_relocations_early(&self) -> bool {}
// DT_INIT_ARRAY, DT_INIT_ARRAYSZ
pub fn initialization_functions_iter(&self) -> impl Iterator<Item = u64> {}
// DT_FINI_ARRAY, DT_FINI_ARRAYSZ
pub fn termination_functions_iter(&self) -> impl Iterator<Item = u64> {}
// DT_INIT
pub fn flags(&self) -> Option<u64> {}
// DT_PREINIT_ARRAY, DT_PREINIT_ARRAYSZ
pub fn pre_initialization_functions_iter(&self) -> impl Iterator<Item = u64> {}
} where: pub struct ProcedureLinkageTableRelocations64 {
pub address: u64,
pub total_size: u64,
pub relocations_type: u64,
}
pub struct StringTable64 {
pub address: u64,
pub total_size: u64,
}
pub struct SymbolTable64 {
pub address: u64,
pub entry_size: u64,
}
pub struct RelocationTable64 {
pub address: u64,
pub total_size: u64,
pub entry_size: u64,
}
pub struct LibrarySearchPaths<'elf> {
pub rpath: DynamicTagsLibrarySearchPathIter<'elf>,
pub runpath: DynamicTagsLibrarySearchPathIter<'elf>,
}
struct DynamicTagsIter64<'elf> {}
impl<'elf> Iterator for DynamicTagsIter64<'elf> {
type Item = (NonZeroU64, u64);
fn next(&mut self) -> Option<Self::Item> {}
}
struct DynamicTagsNeededIter64<'elf> {}
impl<'elf> Iterator for DynamicTagsNeededIter64<'elf> {
type Item = &'elf CStr;
fn next(&mut self) -> Option<Self::Item> {}
}
pub struct DynamicTagsLibrarySearchPathIter<'elf> {}
impl<'elf> Iterator for DynamicTagsLibrarySearchPathIter<'elf> {
type Item = &'elf CStr;
fn next(&mut self) -> Option<Self::Item> {}
} |
While this is correct according to the sysv ABI, recent version of gnu ld have stopped emitting I'm unsure of what "recent" means here, but at the very least programs built on Ubuntu 22.04 do not include a |
@koutheir thanks for taking time to write this up and the api proposal. So this would be a moderate breaking change, and tentatively i'm ok with it. Some initial thoughts after reading your proposal:
Anyway, those are my initial concerns, mostly:
|
Can you explain what you mean?
I'm not sure I understand the approach taken in goblin. I effectively observed this reuse of ELF abbreviations in the goblin interface, reflecting the ELF structures underneath, but then I also see issues such as #345 where assumptions are made just to give the illusion that strings are UTF-8 character sequences inside the ELF string table. I think we need to stick to a specific level of abstraction and remain consistent. Please let me know which level of abstraction I should assume.
The approach I take in my crates, in order to fix this issue, is to use the
For example, in my
What is $size is this context?
I agree, but then again, which level of abstraction am I to assume. Should I give the actual information, even if it means handing out
This is problematic, because there is nothing in the documentation or API that indicates that these values are file offsets, instead of (what ELF documents) virtual addresses. I don't expect people to read the crate's source code to figure out why they are getting the wrong number in these fields.
I'm very grateful for goblin, and the effort that went into it, and allowing the community to enjoy it. However, I feel the API still needs breaking changes.
I agree, and I value consistency. Because of that, I think we need to either (1) adapt the interface to make it more like the rest of the crate, or (2) adapt the crate and make it more like this interface. I vote for (2). |
In ELF, the
DT_JMPREL
dynamic array tag is optional, and can be present (holding an address value) or absent. The value of that tag is exposed asgoblin::elf::dynamic::DynamicInfo.jmprel
, which is of typeusize
.DynamicInfo.jmprel
is set to zero ifDT_JMPREL
is absent from the ELF file.Therefore, based on the definition of
goblin::elf::dynamic::DynamicInfo
, there is no way to differentiate the absence ofDT_JMPREL
from its presence with the value zero, because zero can be a valid address, especially in privileged mode and in embedded systems.I think
DT_JMPREL
should be exposed byDynamicInfo
as optional information. We should make the type ofDynamicInfo.jmprel
anOption<usize>
instead.The text was updated successfully, but these errors were encountered: