Linux glibc中的mmap实现-带有符号mmap的动态库

Linux glibc中的mmap实现-带有符号mmap的动态库,linux,linux-kernel,operating-system,system-calls,mmap,Linux,Linux Kernel,Operating System,System Calls,Mmap,我想看看Linux内核函数mmap是如何实现的,所以我从。我下载了glibc-2.27,因为ldd版本告诉我我正在使用glibc 2.27 现在为了找到mmap的定义,我做了grep-r mmapvoid*,它没有返回任何内容,所以我尝试了grep-r mmap void*,它返回以下内容: conform/data/sys/mman.h-data:function {void*} mmap (void*, size_t, int, int, int, off_t) include/sys/mm

我想看看Linux内核函数mmap是如何实现的,所以我从。我下载了glibc-2.27,因为ldd版本告诉我我正在使用glibc 2.27 现在为了找到mmap的定义,我做了grep-r mmapvoid*,它没有返回任何内容,所以我尝试了grep-r mmap void*,它返回以下内容:

conform/data/sys/mman.h-data:function {void*} mmap (void*, size_t, int, int, int, off_t)
include/sys/mman.h:extern void *__mmap (void *__addr, size_t __len, int __prot,
malloc/memusage.c:mmap (void *start, size_t len, int prot, int flags, int fd, off_t offset)
manual/llio.texi:@deftypefun {void *} mmap (void *@var{address}, size_t @var{length}, int @var{protect}, int @var{flags}, int @var{filedes}, off_t @var{offset})
misc/sys/mman.h:extern void *mmap (void *__addr, size_t __len, int __prot,
misc/mmap.c:__mmap (void *addr, size_t len, int prot, int flags, int fd, off_t offset)
support/xunistd.h:void *xmmap (void *addr, size_t length, int prot, int flags, int fd);
support/xmmap.c:xmmap (void *addr, size_t length, int prot, int flags, int fd)
sysdeps/unix/sysv/linux/mmap.c:__mmap (void *addr, size_t len, int prot, int flags, int fd, off_t offset)
sysdeps/mach/hurd/dl-sysdep.c:__mmap (void *addr, size_t len, int prot, int flags, int fd, off_t offset)
sysdeps/mach/hurd/mmap.c:__mmap (void *addr, size_t len, int prot, int flags, int fd, off_t offset)
/* `mmap' replacement.  We do not have to keep track of the size since
   `munmap' will get it as a parameter.  */
void *
mmap (void *start, size_t len, int prot, int flags, int fd, off_t offset)
{
  void *result = NULL;

  /* Determine real implementation if not already happened.  */
  if (__glibc_unlikely (initialized <= 0))
    {
      if (initialized == -1)
        return NULL;

      me ();
    }

  /* Always get a block.  We don't need extra memory.  */
  result = (*mmapp)(start, len, prot, flags, fd, offset);

  ...

  /* Return the pointer to the user buffer.  */
  return result;
}
在所有关于mmap而非_mmap的结果中,我发现mmap的定义在malloc/memusage.c中,它将mmap定义为:

conform/data/sys/mman.h-data:function {void*} mmap (void*, size_t, int, int, int, off_t)
include/sys/mman.h:extern void *__mmap (void *__addr, size_t __len, int __prot,
malloc/memusage.c:mmap (void *start, size_t len, int prot, int flags, int fd, off_t offset)
manual/llio.texi:@deftypefun {void *} mmap (void *@var{address}, size_t @var{length}, int @var{protect}, int @var{flags}, int @var{filedes}, off_t @var{offset})
misc/sys/mman.h:extern void *mmap (void *__addr, size_t __len, int __prot,
misc/mmap.c:__mmap (void *addr, size_t len, int prot, int flags, int fd, off_t offset)
support/xunistd.h:void *xmmap (void *addr, size_t length, int prot, int flags, int fd);
support/xmmap.c:xmmap (void *addr, size_t length, int prot, int flags, int fd)
sysdeps/unix/sysv/linux/mmap.c:__mmap (void *addr, size_t len, int prot, int flags, int fd, off_t offset)
sysdeps/mach/hurd/dl-sysdep.c:__mmap (void *addr, size_t len, int prot, int flags, int fd, off_t offset)
sysdeps/mach/hurd/mmap.c:__mmap (void *addr, size_t len, int prot, int flags, int fd, off_t offset)
/* `mmap' replacement.  We do not have to keep track of the size since
   `munmap' will get it as a parameter.  */
void *
mmap (void *start, size_t len, int prot, int flags, int fd, off_t offset)
{
  void *result = NULL;

  /* Determine real implementation if not already happened.  */
  if (__glibc_unlikely (initialized <= 0))
    {
      if (initialized == -1)
        return NULL;

      me ();
    }

  /* Always get a block.  We don't need extra memory.  */
  result = (*mmapp)(start, len, prot, flags, fd, offset);

  ...

  /* Return the pointer to the user buffer.  */
  return result;
}
我计算结果=*mmappstart,len,prot,flags,fd,offset;重要的是,在这个文件中,还有两个部分处理这个mmapp函数指针,它们是:

声明:静态无效**mmapp void*,大小,int,int,int,off; 在某个名为me的函数中初始化:mmapp=void**void*,size_t,int,int,int,off_tdlsym RTLD_NEXT,mmap; 根据,dlsym函数接受dlopen返回的动态库句柄和以null结尾的符号名,返回该符号加载到内存中的地址。 因此,整个过程可以总结如下:

mmap调用指针mmapp指向的函数 mmapp设置为指向加载到内存中的动态库中的符号mmap 但我找不到任何关于符号为mmap的动态库的信息。 我在代码分析过程中是否做错了什么?我在代码分析方面没有太多的经验,更不用说研究系统调用函数或内核代码了,所以任何建议或正确的方向都将非常感谢。
提前谢谢

Linux内核有多个不同的mmap系统调用,在不同的版本和体系结构中它们并不相同。libc mmap函数对其进行抽象,并将POSIX接口呈现给用户。然而,Glibc代码由于其也针对非Linux平台而变得复杂,并且对于off_t/off64_t转换的所有部分都有代码路径,请参阅以获取有关这方面的更多信息。您可以更轻松地找到一种替代的最小libc,如musl,它只针对现代Linux,不追求历史或完整的POSIX兼容性

在musl的例子中:原型和常量在。在大多数情况下,实现是在移交给syscallSYS_mmap2之前进行一些参数处理

在Glibc的例子中:原型在。常数是分散的,因为并非所有平台都是相同的;例如,参见。实际的定义在中,与musl的一样,在大多数情况下,它在传递给syscallSYS_mmap2之前会进行一些参数处理

无论如何,libc中的mmap只能与内核支持一起工作。因此@NateEldredge评论说这相当无趣

顺便说一下,您在中看到的并不是您正在使用的mmap的定义。这将被构建到一个单独的libmemusage库中,该库将拦截mmap调用,并围绕这些调用添加一些跟踪。您的发行版可能会也可能不会发货;如果是这样,您必须选择使用它,方法是使用LD_PRELOAD=libmemusage.so运行您的程序,这就是包装器脚本的实际功能。这就是它使用dlsym的原因:它定义了一个替换mmap符号,但需要查找原始mmap才能包装对它的调用

在Linux内核中,在大多数体系结构上,SYS_mmap2映射到SYS_mmap_pgoff,定义如下

SYSCALL\u DEFINE6mmap\u pgoff,无符号长,addr,无符号长,len, 无符号长,保护,无符号长,标志, 无符号长,fd,无符号长,pgoff 如果给定一个文件描述符,它将导致调用

结构文件{ const struct file_操作{ int*mmap结构文件*,结构vm_区域_结构*; }*f_op; }
当由提供该文件的文件系统定义时,从的回调。它们有各种不同的实现,但一般来说,它们会向进程的pagetable中添加一个新的vma,这会使其他内核机器将特定的页面映射到进程中,或者在该区域内进行pagefaults调用回文件系统,以提供当时要映射的页面。

Linux内核有多个不同的mmap系统调用,并且它们在不同的版本和体系结构中并不相同。libc mmap函数对其进行抽象,并将POSIX接口呈现给用户。然而,Glibc代码由于其也针对非Linux平台而变得复杂,并且对于off_t/off64_t转换的所有部分都有代码路径,请参阅以获取有关这方面的更多信息。您可以更轻松地找到一种替代的最小libc,如musl,它只针对现代Linux,不追求历史或完整的POSIX兼容性

在musl的例子中:原型和常量在。在大多数情况下,实现是在移交给syscallSYS_mmap2之前进行一些参数处理

在Glibc的例子中:原型在。C 由于并非所有平台都是相同的,因此onstants是分散的;例如,参见。实际的定义在中,与musl的一样,在大多数情况下,它在传递给syscallSYS_mmap2之前会进行一些参数处理

无论如何,libc中的mmap只能与内核支持一起工作。因此@NateEldredge评论说这相当无趣

顺便说一下,您在中看到的并不是您正在使用的mmap的定义。这将被构建到一个单独的libmemusage库中,该库将拦截mmap调用,并围绕这些调用添加一些跟踪。您的发行版可能会也可能不会发货;如果是这样,您必须选择使用它,方法是使用LD_PRELOAD=libmemusage.so运行您的程序,这就是包装器脚本的实际功能。这就是它使用dlsym的原因:它定义了一个替换mmap符号,但需要查找原始mmap才能包装对它的调用

在Linux内核中,在大多数体系结构上,SYS_mmap2映射到SYS_mmap_pgoff,定义如下

SYSCALL\u DEFINE6mmap\u pgoff,无符号长,addr,无符号长,len, 无符号长,保护,无符号长,标志, 无符号长,fd,无符号长,pgoff 如果给定一个文件描述符,它将导致调用

结构文件{ const struct file_操作{ int*mmap结构文件*,结构vm_区域_结构*; }*f_op; }
当由提供该文件的文件系统定义时,从的回调。它们有各种不同的实现,但一般来说,它们会向进程的pagetable中添加一个新的vma,这会使其他内核机器将特定的页面映射到进程中,或者在该区域内进行pagefaults调用回文件系统,以提供当时要映射的页面。

这些都不是您感兴趣的,因为在库的底部,您将看到的只是系统调用。这里真正的操作都在内核中。例如,见。但是你可能更喜欢看一些旧的或玩具操作系统,在这些操作系统中,代码可能更简单,可读性更强。@NateEldredge嘿,我认为这实际上可能非常有用。但是我想你可以从我的问题中看出,我对Linux内核的东西不是很熟悉-我想问,在mmap的手册中,它说我们需要包含,但git中没有名为sys的目录,有Linux/include/Linux/mman.h,但它没有mmap定义或声明。。。我是不是误解了什么?这个故事太长了,不能评论。另问一个问题。是有点相关的,虽然这些都不是你感兴趣的,因为在底部,你将在库中看到的只是一个系统调用。这里真正的操作都在内核中。例如,见。但是你可能更喜欢看一些旧的或玩具操作系统,在这些操作系统中,代码可能更简单,可读性更强。@NateEldredge嘿,我认为这实际上可能非常有用。但是我想你可以从我的问题中看出,我对Linux内核的东西不是很熟悉-我想问,在mmap的手册中,它说我们需要包含,但git中没有名为sys的目录,有Linux/include/Linux/mman.h,但它没有mmap定义或声明。。。我是不是误解了什么?这个故事太长了,不能评论。另问一个问题。不过,这有点相关