mmap doesn’t fly

I’m running CentOS 5.4 (Linux dustpuppy.lakemasoniccenter.org 2.6.18-164.9.1.el5 #1 SMP Tue Dec 15 21:04:57 EST 2009 i686 athlon i386 GNU/Linux).  I have the following demo program:

#include 
#include 
#include 
#include 
#include 

int main(int argc, char *argv[]) {
        FILE *fd = fopen("/tmp/readme", "r");
        while (!feof(fd)) {
                putc(getc(fd), stdout);
        }

        rewind(fd);
        int *ra = mmap(NULL, 8, PROT_READ, MAP_SHARED, fd, NULL);
        munmap(ra, 8);
        close(fd);
        return errno;
}

This is what it does:

dustpuppy 106% strace ./mmap
execve("./mmap", ["./mmap"], [/* 34 vars */]) = 0
brk(0)                                  = 0x98a6000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY)      = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=57362, ...}) = 0
mmap2(NULL, 57362, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7f20000
close(3)                                = 0
open("/lib/libc.so.6", O_RDONLY)        = 3
read(3, "\177ELF\1\1\1\3\3\1\340\277=004"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1611564, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7f1f000
mmap2(0x3c6000, 1332676, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x3c6000
mprotect(0x505000, 4096, PROT_NONE)     = 0
mmap2(0x506000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x13f) = 0x506000
mmap2(0x509000, 9668, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x509000
close(3)                                = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7f1e000
set_thread_area({entry_number:-1 -> 6, base_addr:0xb7f1e6c0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
mprotect(0x506000, 8192, PROT_READ)     = 0
mprotect(0x3c2000, 4096, PROT_READ)     = 0
munmap(0xb7f20000, 57362)               = 0
brk(0)                                  = 0x98a6000
brk(0x98c7000)                          = 0x98c7000
open("/tmp/readme", O_RDONLY)           = 3
fstat64(3, {st_mode=S_IFREG|0600, st_size=20, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7f2e000
read(3, "I'm a little teapot\n", 4096)  = 20
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7f2d000
write(1, "I'm a little teapot\n", 20I'm a little teapot
)   = 20
read(3, "", 4096)                       = 0
_llseek(3, 0, [0], SEEK_SET)            = 0
mmap2(NULL, 8, PROT_READ, MAP_SHARED, 160063496, 0) = -1 EBADF (Bad file descriptor)
munmap(0xffffffff, 8)                   = -1 EINVAL (Invalid argument)
close(160063496)                        = -1 EBADF (Bad file descriptor)
write(1, "\377", 1ÿ)                     = 1
exit_group(9)                           = ?

Why can I read from the file just fine with a read() or getc() call but have mmap() tell me that it’s a bad fd? That doesn’t make sense. Can any UNIX/C geeks help me out here? Thanks!

Advertisements
  1. #1 by Joshua on January 20, 2010 - 3:25 PM

    Fuck wordpress. It turned my 8 ) in the munmap() call into a stupid smiley.

    • #2 by Chadwick on January 20, 2010 - 3:42 PM

      Lol. Over at Balloon Juice, some posts are just tagged “FYWP” or “Fuck you, WordPress” for whatever WordPress did while they were trying to post.

  2. #3 by Joshua on January 20, 2010 - 3:57 PM

    This is what gcc -g -S turns the mmap() call into:

    
     64         .loc 1 14 0
     65         leal    -16(%ebp), %eax
     66         movl    $0, 20(%esp)
     67         movl    %eax, 16(%esp)
     68         movl    $1, 12(%esp)
     69         movl    $1, 8(%esp)
     70         movl    $8, 4(%esp)
     71         movl    $0, (%esp)
     72         call    mmap
     73         movl    %eax, -12(%ebp)
    

    Now, on this site, they're pretty much doing exactly what I want to do. They wrote it in AT&T syntax assembly longhand. I notice that I get the fd's address into EAX by doing leal -16(%ebp), %eax while the site does

    movl	$fd,%ebx	// load file descriptor
    movl	(%ebx),%eax
    

    , which replaces the LEA instruction with an immediate value ($fd) and then moves the pointer to EAX. I'm not sure if that's equivalent or not. Or am I overthinking this mmap() thing?

    • #4 by Joshua on January 20, 2010 - 4:11 PM

      BTW, doing a movl $x, y(%esp) is equivalent to doing a pushl $x, since ESP is the stack pointer. So lines 66 – 71 are pushing the arguments onto the stack in prep for the function call.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: