--
-----------------------------------------------------------------
| Phil Howard - KA9WGN | Dallas | http://linuxhomepage.com/ |
| phil-...@ipal.net | Texas, USA | http://phil.ipal.org/ |
-----------------------------------------------------------------
Probably not "in some simple way," and this is a deficiency of Linux.
There ought to be an equivalent to the VirtualQuery() of Win32, but
the best that Linux offers in that line is to parse /proc/self/maps
and avoid files whose names contain '\n' or "rw-p" etc.
If you are dealing with vanilla ELF, then
-----
#include <link.h>
#include <dlfcn.h> /* cc ... -ldl */
main()
{
struct link_map const *const lm = dlopen(0, RTLD_LAZY);
/* look at .l_addr in the list *lm, *lm->l_next, ... */
return 0;
}
-----
comes close in many ways. However, for an ET_EXEC file, link_map.l_addr
is 0 because l_addr is actually a relocation value, not a base
address; an ET_EXEC file needs no relocation. glibc 2.2.* has
hidden the fields .l_map_start and .l_map_end, which provide some
clues (see the full structure definition in the elf/ directory
of the glibc sources.) The fields .l_phdr and .l_phnum are also
useful, but also hidden.
Another entrance to this problem is the DT_DEBUG field of PT_DYNAMIC
(see <elf.h>) or "extern Elf32_Dyn _DYNAMIC[];". See <link.h>.
The pseudo file /proc/self/exe can also be parsed for Elf32_Ehdr
and Elf32_Phdr; or readlink()ed, etc.
And if your program doesn't do putenv(), then the Elf32_auxv_t
array which follows the 0 that terminates the pointers to
environment strings can be inspected for AT_PHDR etc.
--
John Reiser, jre...@BitWagon.com
#include <asm/ioctl.h>
struct vma_info {
int64 offset; /* in fd below */
unsigned long address; /* IN: query address; OUT: base of region */
unsigned long length; /* of region */
unsigned int flags; /* VM_* flags */
int fd; /* apply fstat(), etc; remember to close(). */
};
/* If no vma covers an address, then a pseudo-region is returned,
such that length+address is the beginning of the next vma,
and flags will be all-zero [or something...], and ~0==fd.
*/
#define VMA_GET _IOWR('V', 1, struct vma_info)
/* example: enumerate the address space */
int const maps = open("/proc/self/maps", O_RDONLY, 0);
unsigned long addr = 0;
for (;;) {
struct vma_info info;
info.address = addr;
if (0!=ioctl(maps, VMA_GET, &info)) {
/* check errno, etc. */
break; /* done enumerating */
}
/* examine info _now_ */
close(info.fd);
addr += info.length;
}
close(maps);
--
John Reiser, jre...@BitWagon.com
phil-new...@ipal.net wrote:
Couldn't you copy your executable into a ram disk and
run from there? I assume you want to umount some other "real"
disk. If not, please ignore me.
eric
Actually, that _is_ where it is running from. It is the ram disk
I want to unmount.
I'm considering just grabbing some memory via mmap(), copying the
program code into there (hopefully that part gets done right) then
unmapping everything else in the whole address space.
I think you can just munmap() everything except
the few ranges you need to preserve. It is legal
to munmap ranges that are not currently mapped.
I had something similar to this in mind
{
int psize=getpagesize();
munmap(psize,protected-psize);
munmap(protected+psize,
(((stackpointer-protected)/psize)-3)*psize);
}
--
Kasper Dupont