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

정진하*_*정진하 1 linux operating-system mmap system-calls linux-kernel

我想看看Linux内核功能是如何实现的,所以我从GNU页面mmap()下载了GNU C Library( )源码。(我下载是因为告诉我我正在使用) 现在找到我所做的定义,它什么也没返回,所以我尝试返回以下内容:glibcglibc-2.27ldd --versionGLIBC 2.27
mmap()grep -r "mmap(void" *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)
Run Code Online (Sandbox Code Playgroud)

在所有关于mmap()和不关于的结果中,我发现的__mmap()定义mmap()如下:malloc/memusage.cmmap()

/* `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;
}
Run Code Online (Sandbox Code Playgroud)

我认为result = (*mmapp)(start, len, prot, flags, fd, offset);重要的是,在这个文件中还有另外两个部分处理这个mmapp函数指针,它们是:

  1. 宣言:static void *(*mmapp) (void *, size_t, int, int, int, off_t);
  2. 在某个名为 的函数中进行初始化me():根据手册mmapp = (void *(*)(void *, size_t, int, int, int, off_t))dlsym (RTLD_NEXT, "mmap");
    , 该函数采用 dlopen() 返回的动态库的“句柄”和以 null 结尾的符号名称,返回该符号加载到内存中的地址。dlsym()

因此,整个过程可以总结如下:

  1. mmap()调用指针指向的函数mmapp
  2. mmapp设置为指向"mmap"加载到内存的动态库中的符号

但我找不到任何有关带有符号的动态库的信息"mmap"
我在代码分析的过程中做错了什么吗?我在代码分析方面没有太多经验,更不用说研究系统调用函数或内核代码,因此任何建议或正确方向的推动将不胜感激。
提前致谢!

eph*_*ent 5

Linux 内核有多个不同的mmap系统调用,并且它们在不同版本和体系结构中并不相同。libcmmap函数对其进行抽象并向用户呈现 POSIX 接口。然而,Glibc 代码很复杂,因为它也针对非 Linux 平台,并且具有off_t/off64_t转换所有部分的代码路径(有关更多信息,请参阅Glibc 手册 \xc2\xa7 功能测试宏)。您可以更轻松地寻找替代的最小 libc,例如 musl,它仅针对现代 Linux,并不旨在实现历史兼容性或完整的 POSIX 兼容性。

\n

在 musl 的情况下:原型和常量位于include/sys/mman.h中。实现在src/mman/mmap.c中,它在移交之前进行一些参数处理syscall(SYS_mmap2)(在大多数情况下)。

\n

在 Glibc 的例子中:原型位于Misc/sys/mman.h中。常量是分散的,因为并非所有平台都相同;请参阅bits/mman.hsysdeps/unix/sysv/linux/bits/mman-shared.hsysdeps/unix/sysv/linux/bits/mman-map-flags-generic.hsysdeps/unix/sysv/linux例如/x86/bits/mman.h 。实际的定义位于sysdeps/unix/sysv/linux/mmap.c中,并且像 musl 一样,它在移交之前会进行一些参数处理syscall(SYS_mmap2)(在大多数情况下)。

\n

不管怎样,mmaplibc 只能在内核支持下工作。因此@NateEldredge 评论说它相当无趣。

\n

顺便说一句,您在malloc/memusage.c中看到的并不是您正在使用定义。mmap它被内置到一个单独的libmemusage库中,该库拦截mmap调用(以及其他调用)并在它们周围添加一些跟踪。您的发行版可能会也可能不会发货;如果是这样,您必须通过运行程序来选择使用它LD_PRELOAD=libmemusage.so(这实际上是memusage包装器脚本的作用)。这就是它使用 的原因dlsym:它定义了一个替换mmap符号,但需要查找原始符号mmap才能包装对其的调用。

\n

在 Linux 内核中,SYS_mmap2映射到sys_mmap_pgoff大多数架构,在mm/mmap.c中定义为

\n
SYSCALL_DEFINE6(mmap_pgoff, unsigned long, addr, unsigned long, len,\n        unsigned long, prot, unsigned long, flags,\n        unsigned long, fd, unsigned long, pgoff)\n
Run Code Online (Sandbox Code Playgroud)\n

如果给定一个文件描述符,它会导致调用

\n
struct file {\n    const struct file_operations {\n        int (*mmap) (struct file *, struct vm_area_struct *);\n    } *f_op;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

由提供该文件的文件系统定义时的回调(来自include/linux/fs.h )。它们有各种不同的实现,但通常它们会向进程的页表添加一个新的 vma,这要么使其他内核机器将特定页面映射到进程中,要么使该区域内的页面错误回调到文件系统以提供页面到时候就可以映射了。

\n