mirror of
https://github.com/genodelabs/genode.git
synced 2025-02-20 17:52:52 +00:00
ldso: heuristics for libs needed during execve
The allocation of regions within the linker area is normally left to the best-fit 'Allocator_avl', which happens to populate the linker area starting with the binary followed by all loaded libraried with no gaps in between. When replacing the binary during execve, however, we need to ensure that the new binary does not conflict with any library that stays resident during execve. This patch tweaks the linker's region allocation scheme such that these libraries are placed at the end of the linker area. Issue #3481
This commit is contained in:
parent
fa48054959
commit
66d5359d75
@ -117,7 +117,32 @@ struct Linker::Elf_file : File
|
||||
return rom_connection->dataspace();
|
||||
}
|
||||
|
||||
Elf_file(Env &env, Allocator &md_alloc, char const *name, bool load)
|
||||
void _allocate_region_within_linker_area(Name const &name)
|
||||
{
|
||||
bool const binary = (start != 0);
|
||||
|
||||
if (binary) {
|
||||
Region_map::r()->alloc_region_at(size, start);
|
||||
reloc_base = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Assign libraries that must stay resident during 'execve' to
|
||||
* the end of the linker area to ensure that the newly loaded
|
||||
* binary has enough room within the linker area.
|
||||
*/
|
||||
bool const resident = (name == "libc.lib.so")
|
||||
|| (name == "libm.lib.so")
|
||||
|| (name == "posix.lib.so")
|
||||
|| (strcmp(name.string(), "vfs", 3) == 0);
|
||||
|
||||
reloc_base = resident ? Region_map::r()->alloc_region_at_end(size)
|
||||
: Region_map::r()->alloc_region(size);
|
||||
start = 0;
|
||||
}
|
||||
|
||||
Elf_file(Env &env, Allocator &md_alloc, Name const &name, bool load)
|
||||
:
|
||||
env(env), rom_cap(_rom_dataspace(name)), loaded(load)
|
||||
{
|
||||
@ -133,8 +158,10 @@ struct Linker::Elf_file : File
|
||||
if (load && !Region_map::r().constructed())
|
||||
Region_map::r().construct(env, md_alloc, start);
|
||||
|
||||
if (load)
|
||||
if (load) {
|
||||
_allocate_region_within_linker_area(name);
|
||||
load_segments();
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~Elf_file()
|
||||
@ -239,10 +266,6 @@ struct Linker::Elf_file : File
|
||||
/* search for PT_LOAD */
|
||||
loadable_segments(p);
|
||||
|
||||
/* allocate region */
|
||||
reloc_base = Region_map::r()->alloc_region(size, start);
|
||||
reloc_base = (start == reloc_base) ? 0 : reloc_base;
|
||||
|
||||
if (verbose_loading)
|
||||
log("LD: reloc_base: ", Hex(reloc_base),
|
||||
" start: ", Hex(start),
|
||||
|
@ -47,6 +47,7 @@ class Linker::Region_map
|
||||
Region_map_client _rm { _env.pd().linker_area() };
|
||||
Allocator_avl _range; /* VM range allocator */
|
||||
addr_t const _base; /* base address of dataspace */
|
||||
addr_t _end = _base + Pd_session::LINKER_AREA_SIZE;
|
||||
|
||||
protected:
|
||||
|
||||
@ -65,23 +66,32 @@ class Linker::Region_map
|
||||
static Constructible_region_map &r();
|
||||
|
||||
/**
|
||||
* Reserve VM region of 'size' at 'vaddr'. Allocate any free region if
|
||||
* 'vaddr' is zero
|
||||
* Allocate region anywhere within the region map
|
||||
*/
|
||||
addr_t alloc_region(size_t size, addr_t vaddr = 0)
|
||||
addr_t alloc_region(size_t size)
|
||||
{
|
||||
addr_t addr = vaddr;
|
||||
|
||||
if (addr && (_range.alloc_addr(size, addr).error()))
|
||||
addr_t result = 0;
|
||||
if (_range.alloc_aligned(size, (void **)&result,
|
||||
get_page_size_log2()).error())
|
||||
throw Region_conflict();
|
||||
else if (!addr &&
|
||||
_range.alloc_aligned(size, (void **)&addr,
|
||||
get_page_size_log2()).error())
|
||||
{
|
||||
throw Region_conflict();
|
||||
}
|
||||
|
||||
return addr;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate region at specified 'vaddr'
|
||||
*/
|
||||
void alloc_region_at(size_t size, addr_t vaddr)
|
||||
{
|
||||
if (_range.alloc_addr(size, vaddr).error())
|
||||
throw Region_conflict();
|
||||
}
|
||||
|
||||
addr_t alloc_region_at_end(size_t size)
|
||||
{
|
||||
_end -= align_addr(size, get_page_size_log2());
|
||||
alloc_region_at(size, _end);
|
||||
return _end;
|
||||
}
|
||||
|
||||
void free_region(addr_t vaddr) { _range.free((void *)vaddr); }
|
||||
|
Loading…
x
Reference in New Issue
Block a user