问题
I'm writing a very simple process loader for Linux. The executables I'm loading are already compiled, and I know where each one expects to be found in memory. The first approach I tried was using mmap()
to manually place each code or data section at the correct location, like
mmap(addr, size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0)
which segfaults unless I remove the MAP_FIXED flag because, it seems, the address of one block conflicts with something already in memory, possibly even the loader itself; the address 0x401000
seems to be the problematic one.
I'm not really even sure where to begin with this one. A friend suggested virtualizing memory access operations; I'm not sure what kind of performance hits I'd take for that, and I have no clue how it's done, but it might be an option. What I'd really love to do is create an "empty" process, which would have, as far as it was concerned, full run of the memory, so nothing would be loaded into the user space until I wanted it to be. The whole concept of an "empty" process might be meaningless, but it's the best way to describe what I want. I'm pretty desperate for some references or examples that might help me.
回答1:
With your process running (maybe snoozing in "sleep(1000);"), look at its /proc/pid/maps. That will tell you what 0x401000 is used for.
~$ sleep 1h &
[3] 2033
~$ cat /proc/2033/maps
00110000-002af000 r-xp 00000000 08:01 1313056 /lib/i386-linux-gnu/libc-2.15.so
...
Here on my box, /bin/sleep doesn't use that block, and neither does my little one-liner program.
You're probably linking in some library which wants to land there?
So one way would be to allocate the block you need way early (long before main() runs -- look elsewhere for that info).
Another way is to link your code to some address you "know" isn't taken (presumably, you're generating the x86 opcodes yourself, or otherwise "linking", so that shouldn't be a stretch).
Another, better, option is to make your code relocatable. The fact that you don't want to replace the entire process's address space (precisely what exec does) more or less says that your code should be just that.
So find a usable address, load the bits there, and, as needed, perform the relocations (so your on-disk file format, if it's not ELF, will need to include reloc info). That's the high road, and the obvious thing you'll want next from your loader.
Of course, that pretty much means reimplementing dlopen() yourself. I assume you're just trying to learn how it works -- if not, man dlopen. Stephane's Rule Zero: it's already there ;-)
Don't forget to support linking other libraries from your code (without duplication), dlclose(), initializers, the various RTLD_* modes, honor MYCUSTOMLD_LIBRARY_PATH, GCC's __thread specifier, etc. ;-)
来源:https://stackoverflow.com/questions/11723758/simple-process-loader-memory-mapping