跟着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,很简单了就学会了使用,加深了理解
本文来自博客园,作者:暴力都不会的蒟蒻,转载请注明原文链接:https://www.cnblogs.com/BobHuang/p/17249834.html