是否可以将函数指针内容存储在C中,我知道您可以在变量中存储各种类型的指针。但是,如果我能够“解开”一个整数指针(指向一个整数)或字符串指针(指向一个无符号字符),我就不能解码一个函数指针了吗?
更清楚的是,我的意思是将机器代码指令存储在一个变量中。
发布于 2017-06-26 09:34:42
您忽略了一个重要的事实:函数在C中不是一个(头等舱)对象。
C中有两种基本类型的指针:数据指针和函数指针。这两种方法都可以使用*取消引用。
相似之处到此为止。数据对象具有存储的值,因此取消引用数据指针访问此值:
int a = 5;
int *b = &a;
int c = *b; // 5一个函数就是这个,一个函数。可以调用函数,因此可以调用取消引用函数指针的结果。它没有存储的值
int x(void) { return 1; }
int (*y)(void) = &x; // valid also without the address-of operator
// ...
int main(void)
{
int a = (*y)(); // valid also without explicit dereference like int a = y();
}为了便于处理,C允许在为函数指针分配函数时省略&操作符,在通过函数指针调用函数时也可以省略显式取消引用。
简而言之:使用指针不会改变数据对象和函数的语义。
还要注意,在这个上下文中,函数和数据指针是不兼容的。不能将函数指针分配给void *。甚至可能有一个平台,其中函数指针的大小与数据指针不同。
实际上,在函数指针具有与数据指针相同的格式的平台上,您可以通过将指针转换为const char *来“说服”编译器访问位于那里的实际二进制代码。但要注意,这是未定义的行为。
发布于 2017-06-26 09:42:44
C中的指针是内存中某个对象的地址。int *是int的地址,指向函数的指针是将函数的代码存储在内存中的地址。
虽然您可以从内存中的函数地址读取一些字节,但它们只是字节而不是其他字节。您需要知道如何解释这些字节,以便“将机器代码指令存储在变量中”。这里真正的问题是知道在哪里停止,一个函数的代码结束,另一个函数的代码开始。
这些东西不是由语言定义的,它们取决于许多因素:处理器体系结构、操作系统、编译器、编译代码的编译器标志(用于优化f.e.)。
这里的真正问题是:假设您可以“将机器代码指令存储在一个变量中”,您想如何使用它?对于大多数人来说,它只是一个没有意义的字节序列,不能用来执行函数。如果您没有编写编译器、链接器、仿真器、操作系统或其他类似的东西,那么您无法使用函数的机器代码指令进行任何有用的操作。(如果你正在写上面的一篇文章,那么你就知道答案了,你不会在这样或其他地方提出这样的问题。)
发布于 2017-06-26 09:56:32
这里的代码应该是将代码注入到程序中的框架。但是,如果您在诸如Linux或Windows这样的SO中执行它,您将在执行第一个指令fn_ptr点之前得到一个异常。
#include <stdio.h>
#include <malloc.h>
typedef int FN(void);
int main(void)
{
FN * fn_ptr;
char * x;
fn_ptr = malloc(10240);
x = (char *)fn_ptr;
// ... Insert code into x that points the same memory of fn_ptr;
x[0]='\xeb'; x[1]='\xfe'; // jmp $ that is like while(1)
fn_ptr();
return 0;
}如果使用gdb执行此代码,将获得以下结果:
(gdb) l
2 #include <malloc.h>
3
4 typedef int FN(void);
5
6 int main(void)
7 {
8 FN * fn_ptr;
9 char * x;
10
11 fn_ptr = malloc(10240);
12 x = (char *)fn_ptr;
13
14 // ... Insert code into x that points the same memory of fn_ptr;
15 x[0]='\xeb'; x[1]='\xfe'; // jmp $ that is like while(1)
16 fn_ptr();
17
18 return 0;
19 }
(gdb) b 11
Breakpoint 1 at 0x400535: file p.c, line 11.
(gdb) r
Starting program: /home/sergio/a.out
Breakpoint 1, main () at p.c:11
11 fn_ptr = malloc(10240);
(gdb) p fn_ptr
$1 = (FN *) 0x7fffffffde30
(gdb) n
12 x = (char *)fn_ptr;
(gdb) n
15 x[0]='\xeb'; x[1]='\xfe'; // jmp $ that is like while(1)
(gdb) p x[0]
$3 = 0 '\000'
(gdb) n
16 fn_ptr();
(gdb) p x[0]
$5 = -21 '\353'
(gdb) p x[1]
$6 = -2 '\376'
(gdb) s
Program received signal SIGSEGV, Segmentation fault.
0x0000000000602010 in ?? ()
(gdb) where
#0 0x0000000000602010 in ?? ()
#1 0x0000000000400563 in main () at p.c:16
(gdb) 您如何看到GDB在SIGSEGV, Segmentation fault点所在的地址发出信号,尽管我们进入内存的指令是有效的指令。
请注意,LM代码: EB FE只对Intel (或兼容)处理器有效。这个LM代码对应于程序集代码: jmp $。
https://stackoverflow.com/questions/44756476
复制相似问题