首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用C语言解码函数指针

用C语言解码函数指针
EN

Stack Overflow用户
提问于 2017-06-26 09:19:04
回答 5查看 1.7K关注 0票数 2

是否可以将函数指针内容存储在C中,我知道您可以在变量中存储各种类型的指针。但是,如果我能够“解开”一个整数指针(指向一个整数)或字符串指针(指向一个无符号字符),我就不能解码一个函数指针了吗?

更清楚的是,我的意思是将机器代码指令存储在一个变量中。

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2017-06-26 09:34:42

您忽略了一个重要的事实:函数在C中不是一个(头等舱)对象。

C中有两种基本类型的指针:数据指针和函数指针。这两种方法都可以使用*取消引用。

相似之处到此为止。数据对象具有存储的值,因此取消引用数据指针访问此值:

代码语言:javascript
复制
int a = 5;
int *b = &a;
int c = *b; // 5

一个函数就是这个,一个函数。可以调用函数,因此可以调用取消引用函数指针的结果。它没有存储的值

代码语言:javascript
复制
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 *来“说服”编译器访问位于那里的实际二进制代码。但要注意,这是未定义的行为。

票数 4
EN

Stack Overflow用户

发布于 2017-06-26 09:42:44

C中的指针是内存中某个对象的地址。int *int的地址,指向函数的指针是将函数的代码存储在内存中的地址。

虽然您可以从内存中的函数地址读取一些字节,但它们只是字节而不是其他字节。您需要知道如何解释这些字节,以便“将机器代码指令存储在变量中”。这里真正的问题是知道在哪里停止,一个函数的代码结束,另一个函数的代码开始。

这些东西不是由语言定义的,它们取决于许多因素:处理器体系结构、操作系统、编译器、编译代码的编译器标志(用于优化f.e.)。

这里的真正问题是:假设您可以“将机器代码指令存储在一个变量中”,您想如何使用它?对于大多数人来说,它只是一个没有意义的字节序列,不能用来执行函数。如果您没有编写编译器、链接器、仿真器、操作系统或其他类似的东西,那么您无法使用函数的机器代码指令进行任何有用的操作。(如果你正在写上面的一篇文章,那么你就知道答案了,你不会在这样或其他地方提出这样的问题。)

票数 3
EN

Stack Overflow用户

发布于 2017-06-26 09:56:32

这里的代码应该是将代码注入到程序中的框架。但是,如果您在诸如Linux或Windows这样的SO中执行它,您将在执行第一个指令fn_ptr点之前得到一个异常。

代码语言:javascript
复制
#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执行此代码,将获得以下结果:

代码语言:javascript
复制
(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 $。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44756476

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档