跟着chatgpt学mmap

以前对Linux的了解比较少,现在跟着chatgpt来学学,很好玩。
比搜索那堆垃圾博客好太多了,而且咱 chatgpt 中文也很好哦

chatgpt给的mmap解释

mmap是一种UNIX和类UNIX操作系统中的系统调用,用于将文件或者其他对象映射到内存中,从而使得应用程序可以直接访问这些内存中的对象。其核心思想是将一个文件映射到一段虚拟内存中,使得对这段虚拟内存的读写操作被映射到对该文件的读写操作,即使在文件很大的情况下,也只是将部分文件内容映射到内存中,而不是全部读取到内存中。
在操作系统中,每个进程都拥有独立的虚拟地址空间,在其中,程序可以访问到不同的内存区域。当调用mmap系统调用时,内核将为该进程分配一段虚拟内存区域,并将其映射到指定的文件或者共享内存段(anonymous mapping)。这样,程序就可以使用指针访问该文件或共享内存段中的数据,而不需要调用read和write等函数来进行读写操作。
由于mmap采用了预读和延迟写的方式,因此可以显著提高IO效率和对大文件的处理效率,同时减少了进程调用系统调用的次数和系统开销,是一种非常高效的IO操作方式。

chatgpt 给的mmap函数的解释

mmap函数是一个系统调用,用于将一个文件或者共享内存对象映射到调用进程的地址空间中。其函数原型如下:

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);

各个参数的含义如下:

addr:指定映射区域的开始地址,通常设置为NULL,让操作系统自动分配一个合适的地址。

length:指定映射区域的长度,单位是字节。

prot:指定内存保护属性,包括以下选项:

PROT_READ:映射区域的内存可以被读取;
PROT_WRITE:映射区域的内存可以被写入;
PROT_EXEC:映射区域的内存可以被执行;
PROT_NONE:映射区域的内存不能被访问。

flags:指定映射区域的标志,包括以下选项:

MAP_SHARED:表示映射区域与文件共享,对该区域的写入操作会被反映到文件中;
MAP_PRIVATE:表示为调用进程创建一个私有的映射,对该区域的写入操作不会被反映到文件中;
MAP_FIXED:表示要求内核将映射区域映射到指定的起始地址,如果该地址已经被占用则调用失败;
MAP_ANONYMOUS:表示创建一个匿名映射,不与文件关联,通常用于共享内存。

fd:表示要映射的文件描述符,只有在MAP_SHARED标志被设置时才会使用它。

offset:表示文件的偏移量,表示文件从哪里开始映射到内存中,只有在fd参数被使用时才需要设置。

函数返回值是一个指向映射区域的指针,如果失败则返回MAP_FAILED。

chatgpt 给我的读取ELF文件然后跑起来,我验证返回值的程序

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>

int main()
{
    int fd;
    void *addr;
    struct stat sb;

    // 打开程序文件
    fd = open("hello", O_RDONLY);
    if (fd == -1) {
        perror("open");
        exit(EXIT_FAILURE);
    }

    // 获取文件大小
    if (fstat(fd, &sb) == -1) {
        perror("fstat");
        exit(EXIT_FAILURE);
    }

    // 将程序映射到内存中
    addr = mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
    if (addr == MAP_FAILED) {
        perror("mmap");
        exit(EXIT_FAILURE);
    }

    // 关闭文件
    if (close(fd) == -1) {
        perror("close");
        exit(EXIT_FAILURE);
    }

    // 设置内存区域为可执行
    if (mprotect(addr, sb.st_size, PROT_READ | PROT_EXEC) == -1) {
        perror("mprotect");
        exit(EXIT_FAILURE);
    }

    // 调用程序入口地址运行程序
    int (*entry)();
    entry = (int(*)())addr;
    int ret = entry();

    // 释放映射区
    if (munmap(addr, sb.st_size) == -1) {
        perror("munmap");
        exit(EXIT_FAILURE);
    }

    return ret;
}

非常完美,我们只要搞定这个入口地址就可以了,不是objdump的,而是真实的文件位置,我是拿objdump和读二进制文件找到了只需要跳过ELF头的64Byte,很简单了就学会了使用,加深了理解

posted @ 2023-03-23 22:48  暴力都不会的蒟蒻  阅读(136)  评论(0编辑  收藏  举报