Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <ol> <li><p>What happens depends first of all on whether or not you <code>rm /usr/bin/myprog</code> and then create a new one, or whether you <code>open()</code> and <code>write()</code> to the existing <code>/usr/bin/myprog</code>.</p></li> <li><p>If you <code>rm</code> the old <code>/usr/bin/myprog</code> file and then create a new one with the same name, then the kernel/file system driver gives the new version a new inode, and the old inode stays lying around in the <code>/proc</code> filesystem until the process that has it opened closes it. Your existing process <code>/usr/bin/myprog</code> has it's own private version of the file, unmodified, until it <code>close()</code>s the file descriptor.</p></li> <li><p>All operating systems (Windows, Linux, probably OS X) use demand-paged memory mapping (<code>mmap()</code> for posix, I can't remember the equivalent for Windows - <code>VirtualAlloc()</code>?) for process loading. <strike>This way any sections of the executable that don't get touched are never loaded into memory.</strike></p></li> <li><p>If this were a conventional <code>mmap()</code>'d file, and two processes both opened/mapped it, and neither of them specified <code>MAP_PRIVATE</code> (i.e. copy-on-write) in the call to <code>mmap()</code>, then the two processes will essentially be looking at the same physical memory page and, provided both of them called <code>mmap()</code> with <code>PROT_READ</code> | <code>PROT_WRITE</code>, they'll see each other's modifications.</p></li> <li><p><strike>If this were a conventional <code>mmap()</code>'d file, and process 1 had opened/mapped it, and then process 2 started to fiddle around with the file on the hard drive itself through <code>write()</code> calls (not my <code>mmap</code>ing), process 1 does indeed see these changes. I guess the kernel notices that the file is being modified and reloads the affected pages.</strike></p></li> <li><p><strike>I don't know exactly whether there's any special <code>mmap()</code> behaviour for executable images? If I hacked a pointer to one of my functions and modified the code, would it mark the page as dirty? Would the dirty page get written back to <code>/usr/bin/myprog</code>? When I try this, it segfaults, so I guess that while _TEXT pages are mapped in with <code>MAP_SHARED</code>, they also probably don't get <code>PROT_WRITE</code> and therefore segfault when written to. _DATA sections get loaded into memory as well, of course, and those need to be modified, but those can be marked <code>MAP_PRIVATE</code> (copy-on-write) - so they probably wouldn't keep their connection to the <code>/usr/bin/myprog</code> file. </strike></p></li> <li><p><strike>Point 6 concerns the executable modifying itself directly. Point 5 concerned modifying an arbitrary <code>mmap()</code>d file at the <code>write()</code> level. When I try to modify an executable (which is <code>mmap()</code>'d) in another process with <code>write()</code>, I don't get the same results as in point 5. I can make all sorts of horrible changes to the executable with bare <code>write()</code> calls, and nothing happens. Then, when I exit the process and try to run it again, it crashes (of course - after everything I've been doing to the executable file). This confuses me. I can't permute the parameters to <code>mmap()</code> to get it to behave this way - not copy-on-write but not affected by changes to the mapped file. </strike></p></li> <li><p>Well, I went back to the Bible (Stevens) and the big issue is <code>MAP_PRIVATE</code> vs <code>MAP_SHARED</code>. <code>MAP_PRIVATE</code> is copy-on-write and <code>MAP_SHARED</code> isn't. <code>MAP_PRIVATE</code> will make a copy of the mapped page as soon as you make modifications to it. It's undefined whether a modification to the original file will propagate to the mapped <code>MAP_PRIVATE</code> pages, but with OS X they don't. <code>MAP_SHARED</code> maintains the connection to the original file, allowing updates to the file to propagate to the memory pages and vice-versa. If a memory block is mapped <code>MAP_PRIVATE</code>, no modification that you make to it will ever be written to disk. <code>MAP_SHARED</code> OTOH allows modifications to the file through writes to the mapped pages.</p></li> <li><p>The image loader maps executable files as <code>MAP_PRIVATE</code>. This explains the behaviour in point 6 - hacking a pointer to a function's code and then modifying it, even if you had permission to do that, wouldn't write the data back to the disk. Theoretically it should be possible to change the executable <code>/usr/bin/myprog</code> immediately after the OS image loader <code>mmap()</code>'s it, but whenever I look at very large executables with <code>vmmap</code>, their TEXT section always seems to be completely resident. I don't know whether this is because OS X's image loader touches all of the pages to ensure that they get copied up, or whether OS X's page manager is just very aggressive about making pages resident (it is), but I haven't been able to make an executable in OS X whose TEXT section wasn't completely resident as soon as <code>main()</code> started.</p></li> <li><p>The OS X image loader is very aggressive about loading mapped pages. I've noticed that when <code>mmap()</code>'ing a file, it has to be very large before OS X decides to leave any of it non-resident. a 1GB file gets completely loaded, but only about 1.7GB of a 3GB file gets made resident. This is on a machine with 8GB physical RAM and running the 64-bit OS X kernel.</p></li> </ol>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload