作为ASM系统调用的mprotect()在第三个参数方面的用法是什么?

gal*_*gal 2 linux memory assembly memory-management

在i386架构Linux中,我知道您可以通过将syscall的标识加载到EAX中并将参数加载到EBX,ECX等中来构建系统调用.

我很困惑mprotect的第三个参数在这种情况下会是什么样子; 假设我想在二进制文件的已分配内存可执行文件中创建一个内存段,那么编码如何适用于PROT_EXEC参数(arg 3)?我知道前两个参数是(1)指向已分配块的开始的指针,以及(2)在ASM中相对容易概念化的已分配块的长度(因为它们是内存中的十六进制地址) .

如何在Linux上的i386程序集中将mprotect()的第三个参数格式化为中断发出的系统调用?

谢谢.

qdi*_*dii 6

TL; DR:传递整数作为第三个参数.

现在让我们回答评论中的问题.如果你打开mman-common.h,它应该位于/ usr/include/asm-generic中,你会发现这些值.

#define PROT_READ       0x1             /* page can be read */
#define PROT_WRITE      0x2             /* page can be written */
#define PROT_EXEC       0x4             /* page can be executed */
#define PROT_SEM        0x8             /* page may be used for atomic ops */
Run Code Online (Sandbox Code Playgroud)

在编译之前,预处理器将您的参数替换为上面的数字.所以,如果你有这个电话:

mprotect(myaddress, 256, PROT_READ | PROT_WRITE);
Run Code Online (Sandbox Code Playgroud)

它将被此代码替换:

mprotect(myaddress, 256, 0x1 | 0x2);
Run Code Online (Sandbox Code Playgroud)

现在看看不同参数可以采用的值:它们没有被随机选择,它们是2的幂,因此在二进制表示法中它们仅由一个1位和0表示.

PROT_READ  = 0x1 =   00000001
PROT_WRITE = 0x2 =   00000010
PROT_EXEC  = 0x4 =   00000100
Run Code Online (Sandbox Code Playgroud)

选择2的幂是很方便的,因为当您使用二进制OR时,您获得的数字组合了前两个值,因此两个信息都包含在OR编号中.

PROT_WRITE | PROT_EXEC = 
    00000010
  | 00000100
=   00000110
Run Code Online (Sandbox Code Playgroud)

现在回到我们的电话:

如果你曾经打过电话mprotect(myaddress, 256, PROT_READ | PROT_WRITE),会发生什么事情PROT_READ | PROT_WRITE就会被合并到一起0x1 | 0x2,这就是0x3.

现在在内核方面,假设PROT_READ | PROT_WRITE是由用户编写的.内核接收参数0x3,并想检查最初是否编写了PROT_READ.一种方法是写这个:

if (PROT_READ & userValue) { }
Run Code Online (Sandbox Code Playgroud)

它的工作原理是因为userValue包含二进制的PROT_READ和PROT_WRITE的组合版本:

PROT_READ & userValue = 
    00000001
&&  00000011
 =  00000001
Run Code Online (Sandbox Code Playgroud)

如果设置了该标志,则该数字不为零,因此内核知道已标记的标志已通过.

希望这可以帮助.