How the share library be shared by different processes? - linux

I read some documents that share library comiled with -fPIC argument,
the .text seqment of the .so will be shared at process fork's dynamic linking stage
(eq. the process will map the .so to the same physical address)
i am interested in who (the kernel or ld.so ) and how to accomplish this?
maybe i should trace the code, but i dont know where to start it.
Nevertheless, i try to verify the statement.
I decide to check the function address like printf which is in the libc.so that all c program will link.
I get the printf virtual address of the process and need to get the physical address. Tried to write a kernel module and pass the address value to kernel, then call virt_to_phys. But it did not work cause the virt_to_phys only works for kmalloc address.
So, process page table look-at might be the solution to find the virtual address map to physical address. Were there any ways to do page table look-at? Or othere ways can fit the verify experiment?
thanks in advance!

The dynamic loader uses mmap(2) with MAP_PRIVATE and appropriate permissions. You can see what it does exactly by running a command from strace -e file,mmap. For instance:
strace -e file,mmap ls
All the magic comes from mmap(2). mmap(2) creates mappings in the calling process, they are usually backed either by a file or by swap (anonymous mappings). In a file-backed mapping, MAP_PRIVATE means that writes to the memory don't update the file, and cause that page to be backed by swap from that point on (copy-on-write).
The dynamic loader gets the info it needs from ELF's program headers, which you can view with:
readelf -l libfoo.so
From these, the dynamic loader determines what to map as code, read-only data, data and bss (zero-filled segment with zero size in file, non-zero size in memory, and a name only matched in crypticness by Lisp's car and cdr).
So, in fact, code and also data is shared, until a write causes copy-on-write. That is why marking constant data as constant is a potentially important space optimization (see DSO howto).
You can get more info on the mmap(2) manpage, and in Documentation/nommu-mmap.txt (the MMU case, no-MMU is for embedded devices, like ADSL routers and the Nintendo DS).

Shared libraries just a particular use of mapped files.
The address which a file is mapped at in a process's address space has nothing to do with whether it is shared or not.
Pages can be shared even if they are mapped at different addresses.
To find out if pages are being shared, do the following:
Find the address that the file(s) are mapped at by examining /proc/pid/maps
There is a tool which extracts data from /proc/pid/pagemap - find it and use it. This gives you info as to exactly which page(s) of a mapping are present and what physical location they are at
If two processes have a page mapped in at the same physical address, it is of course, shared.

Related

How to determine the memory address range of Linux-Kernel objects

I want to inspect the memory where the functions from kernel/bpf/verifier.c are loaded into.
After compilation to verifier.o the object is linked "into" the kernel. At /proc/kallsyms only non static functions are listed. However I want the addresses of all functions defined in that c file. If kaslr is turned off they should lie sequentially in the kernel space or?
If so is there a way to determine the address range?
Thanks
The solution for my particular problem is to compile the kernel with debug_info=y and obtain the address range from the large vmlinux binary with readelf -Ws vmlinux
However the kernel needs to be bootet with nokalsr or kalsr turned off in the config at compile time.

Throw away dirty copy-on-write pages

Is there a way that I can create a copy-on-write mapping via MAP_PRIVATE, write some data (ie, dirtying some pages), and then discard my changes, without using munmap and re-mmaping? The goal is to maintain the same virtual address for the given mapping (something not guaranteed to happen if I unmap & then mmap the same file again), but to discard all of my COW changes at once.
My understanding is that attempting to re-map the space via hinting the address and using the MAP_FIXED flag may have this effect; however I'm not sure if my interpretation of the MAP_FIXED docs is correct, or if this behaviour is guaranteed.
To quote from the mmap(2) docs:
If the memory region specified by addr and len overlaps pages of any existing
mapping(s), then the overlapped part of the existing mapping(s) will be
discarded.
Does "discarded" in this case mean that any COW pages will be thrown away, and new reads from the corresponding pages will fault and reflect changes on disk?
If you perform a mmap operation which overlaps with existing mappings, the Linux kernel will turf the overlapping part of the existing mappings as if an unmap had been done on them first. So for instance if you map a frame buffer where a shared library used to be, that memory now has nothing to do with the shared library; it points to the frame buffer.
The underlying page object from the removed mapping lives on independently of the mapping: pages are reference counted objects. When two maps share a view of the same page, it's simply due to the same page being "installed" in the different views. When a page is made dirty, and then unmapped, this does not create a dependency whereby the dirty page must be written out prior to the new mapping; the virtual memory can already be re-assigned to a new mapping (such as a piece of a graphics frame buffer) before the original dirty page (for example, part of a file-backed shared mapping) is flushed out.
About throwing away a mapping: I don't think you can do this. That is to say, if you have a mapping which is supposed to flush dirty pages to an underlying file, you cannot write to that memory and then unmap it quickly (or mmap something over it) in hopes that the write is never done. In Linux's madvise API, there is MAP_REMOVE operation which seems relevant, but according to the manual page, it seems to only work on tmpfs and shmfs. I think the only way to block the write from happening would be to do the time-honored ritual known as "dive for the power switch".
There is a way to map a file object such that changes are not propagated: namely, MAP_PRIVATE (opposite to MAP_SHARED). MAP_PRIVATE is needed, for instance, by debuggers like gdb which need to be able to put a breakpoint into an executable or shared library, without throwing a trap instruction into every instance of that executable or library in every running process (and the copy on disk!).
If you have a MAP_PRIVATE with modified parts, and you unmap it (or those parts) or map something over top of them, I believe they will be discarded. Those pages should have been subject to copy-on-write, and so the process which made them dirty should hold the one and only reference. When they are unmapped, their refcount drops to zero and since they are private pages, they get turfed.
The virtual address remains the same even after the copy. Only the physical address changes (and the associated memory mapping page registers).
After the process has written to the page, it is too late to undo it. The copy occurs during the first write to the memory region.

Executing a ELF binary without creating a local file?

Is it possible to execute a binary file without copying it to hard drive?
I know /lib/ld-linux.so.2 can load arbitrary binaries, but that still requires a locally stored file, my thought was to allocate a memory region, duplicate the contents to memory and execute it.
So is that possible?
my thought was to allocate a memory region, duplicate the contents to memory and execute it.
For a statically-linked a.out, you can do just that.
For a dynamically-linked one, you'll need something like dlopen_phdr.
It is possible but very difficult. I worked on a similar problem years ago here. (Caution! That code is incomplete and contains serious bugs.)
The hard part is to make sure that your process's address space requirements do not conflict with the binary's or the dynamic linker's (e.g., /lib/ld-linux.so.2). If you control both programs' memory layout (because you linked them) you can avoid that problem. (My code does not assume such control, and it takes pains to move itself out of the way if necessary.)
If there are no address space conflicts, it is a matter of allocating memory for the exe's PT_LOAD segments (and the linker's, if any), aligning and copying the segments in, protecting the read-only segments, allocating stack, initializing stack and registers the way the kernel does, and jumping to the exe's or linker's entry address.

Allocating specific address in Linux

I would like to allocate a memory in Linux in process at a specific address.
Actually I would like to do something like :
I will have number of process.
Each process will call an initialization function in a library (written by me) which will allocate some memory in address space of the process (which will store process related information). This will be done by each process
Once this memory is allocated, latter the program will call other function in the library. Now these function would like to access the memory allocated (containing process related information) by the first function.
The problem is that i cannot store the address of the memory allocated in the process address space in library (not even in static pointer as there are number of process) and i don't even want user program to store that address. I just don't want user program to know that there is memory allocated by library in their address space. Library function will be abstraction for them and they have to just use them.
Is it possible to to over come this problem.
I was thinking like, whenever any process calls initialization function of library which allocates memory , the memory always gets allocated at same address(say 10000) in all the process irrespective of all other things .
So that any library function which wants to access that memory can easily do by :
char *p=10000;
and then access, which will be access into the address space of the process which called the library function.
Not 100% I got what you are aiming for, but if you want to map memory into a specific set address you can use the MAP_FIXED flag to mmap():
"When MAP_FIXED is set in the flags argument, the implementation is informed that the value of pa shall be addr, exactly. If MAP_FIXED is set, mmap() may return MAP_FAILED and set errno to [EINVAL]. If a MAP_FIXED request is successful, the mapping established by mmap() replaces any previous mappings for the process' pages in the range [pa,pa+len)."
See mmap man page: http://linux.die.net/man/3/mmap
Your question doesnt make sense. As you have worded your question, a global variable in your library would work fine.
Maybe you are saying "a single process might load/unload your library and then load the library again and want the address on the second load". Maybe you are saying "there are 2 libraries and each library needs the same address". Simple. Use setenv() and getenv(). These will store/retrieve anything that can be represented as a string in a variable that has PROCESS WIDE SCOPE....i.e all libraries can see the same environment variables. Simply convert your address to a string (itoa), use setenv() to save it in an environment variable named "__SuperSecretGlobalAddress__", and then use getenv() to retrieve the value.
When your program starts up, a copy of the shell's environment is made for your process. getenv and setenv access and modify that copy. You cannot change the shell's environment with these functions.
See this post.

Code segment sharing between two processes

Suppose we run two processes back to back say :-
$ grep abc abc.txt ==> pid 100
$ grep def def.txt ==> pid 101
I read in the book "Beginning Linux programming" chapter# 11 that the code section of the processes would be shared, as it is read only. Is it so? I think if grep is compiled as shared library only then the code section would be shared.
One more question, in case of shared libraries how does the OS knows that the library has already been loaded or not? Suppose if 2 processes are simultaneously calling a shared library function then how does the virtual address of two processes be converted to physical address pointing the same location in RAM?
The OS doesn't load files into memory anymore. Instead, files are memory mapped. This means an inode and an offset of a file on disk will be connected to a page in memory. This makes it pretty simple to find out if some part of a file has already been loaded. Also, you can keep only part of a file in RAM (after setup, you don't need the setup code anymore, so you can "forget" about it and reuse those pages for something more useful).
The libraries and executables are not loaded, but mapped into memory with mmap(2). Basically, when you mmap() something with MAP_SHARED flag, others who map the same file will get the same memory pages.

Resources