Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/59.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何获取函数上的指针';C语言中的s参数?_C_Dynamic_Macros_Arguments_C Preprocessor - Fatal编程技术网

如何获取函数上的指针';C语言中的s参数?

如何获取函数上的指针';C语言中的s参数?,c,dynamic,macros,arguments,c-preprocessor,C,Dynamic,Macros,Arguments,C Preprocessor,在C语言中是否有一个通用的方法来获取每个参数的指针 你会使用vararg函数吗 特殊语法,如$1、$2、$3 如果没有,是否有一些预处理器宏来定义它 如果在C中不可能,我也对一个客观的C解决方案感兴趣。 我知道我可以在当前方法上使用_cmdspecial hidden获取选择器 参数是否有某种_arg1,_arg2?? 也可以在_cmd之后直接指向内存吗?它是 “安全”考虑参数指针彼此相邻? 更新我自己的问题 如果我使用一些汇编代码访问帧堆栈,我可以获得一个保持 在ebp正确的函数指针上?那么可

在C语言中是否有一个通用的方法来获取每个参数的指针 你会使用vararg函数吗

特殊语法,如$1、$2、$3

如果没有,是否有一些预处理器宏来定义它

如果在C中不可能,我也对一个客观的C解决方案感兴趣。 我知道我可以在当前方法上使用_cmdspecial hidden获取选择器 参数是否有某种_arg1,_arg2?? 也可以在_cmd之后直接指向内存吗?它是 “安全”考虑参数指针彼此相邻?

更新我自己的问题

如果我使用一些汇编代码访问帧堆栈,我可以获得一个保持 在ebp正确的函数指针上?那么可以访问参数吗
同样的方式?很抱歉,如果这是显而易见的,我对汇编程序了解不多。

不,唯一可以做到这一点的方法是使用
stdarg.h

中提供的宏。不,唯一可以做到这一点的方法是使用
stdarg.h

中提供的宏。请参见和a。

参见和a。

不,没有特殊的方法,或任何特殊符号

我想您可以定义一个宏来获取每个参数并生成指向它的指针(找到Boost预处理器库);我肯定我不想

int somefunc(int arg1, char *arg2)
{
    int *p_arg1 = &arg1;
    char **p_arg2 = &arg2;
    ...
}

不,没有特殊的方法,也没有任何特殊的符号

我想您可以定义一个宏来获取每个参数并生成指向它的指针(找到Boost预处理器库);我肯定我不想

int somefunc(int arg1, char *arg2)
{
    int *p_arg1 = &arg1;
    char **p_arg2 = &arg2;
    ...
}

如果变量函数的所有参数都具有相同的类型(例如,
void*
),则可以执行以下操作:

type nth_arg(va_list ap, size_t n)
{
    va_list ap2;
    va_copy(ap2, ap);
    while (n--) va_arg(ap2, type);
    return va_arg(ap2, type);
}

type
替换为实际类型。

如果变量函数的所有参数都具有相同的类型(例如
void*
),可以执行以下操作:

type nth_arg(va_list ap, size_t n)
{
    va_list ap2;
    va_copy(ap2, ap);
    while (n--) va_arg(ap2, type);
    return va_arg(ap2, type);
}

类型
替换为实际类型。

在您的情况下,可以提取当前和以前的堆栈帧指针(即bp寄存器),并使用标准堆栈帧结构确定有多少个4字节(对于32位应用程序)参数单位已在当前例程的调用中传递。您将无法确定哪些单位是char、short或long,以及其中两个单位是否可能是long-long/\uu-int64参数


我想了很久了。考虑一个典型的函数调用“FUNC(A,B)”。调用代码,除非寄存器中有参数(某些x86-32编译器选项和英特尔建议的x86-64),否则代码结果如下

               ; long *esp,*ebp;
push b         ; *(--esp)=b;
push a         ; *(--esp)=a;
call func      ; *(--esp)=return_address_location;
return_address_location:
add esp,8      ; esp+=2;    // free memory allocated for passing parameters
然后,您将使用func进行处理

func:
push ebp       ; *(--esp)=(long) ebp;    // save current ebp <=> current stack frame 
mov ebp,esp    ; ebp=esp;                // create new stack frame in ebp
sub esp,16     ; esp-=4;                 // reserve space for local variables <=> sizeof(long)*4

(func code ...)
func:
推动ebp*(-esp)=(长)ebp;//保存当前ebp当前堆栈帧
mov-ebp,esp;ebp=esp;//在ebp中创建新堆栈帧
副esp,16岁;esp-=4;//为局部变量sizeof(长)*4保留空间
(职能代码…)
现在,当您在func中,需要访问参数时,可以使用ebp+2和ebp+3(*ebp包含以前的ebp,ebp+1返回地址)对其进行寻址。当您需要访问局部变量时,可以使用ebp-4到ebp-1对其进行寻址(如果它们不都是长的,并且设置了一些打包选项,则可能会过于简化)

一段时间后,func完成了它的工作,您需要返回:

mov esp,ebp    ; esp=ebp;         // unreserve space for local variables
pop ebp        ; ebp=*(esp++);    // restore previous ebp <=> previous stack frame
ret            ; eip=*(esp++);    // pop return address into instruction pointer
mov-esp,ebp;esp=ebp;//为局部变量取消保留空间
弹出ebp;ebp=*(esp++);//恢复上一个ebp上一个堆栈帧
ret;eip=*(esp++);//将返回地址弹出到指令指针中
从第一个代码段中,您还将看到第一个堆栈分配(用于传递参数)在返回后是如何被释放的

以下是一些提示:

  • 你自己做数学题 单步执行(通过 指令)通过呼叫/返回 序列,你会得到如何的想法 来解决原来的问题。这个 是基本的堆栈处理,看起来 对所有人来说都差不多 体系结构和实现 知道这件事是件好事
  • 想象一个计算错误的 memset/memcpy到本地缓冲区和 它将如何销毁服务器上的数据 堆栈,包括返回地址, 以前的堆栈帧等
  • 注意ds和ss中的值 (数据和堆栈选择器)和如果 它们包含完全相同的值a 您的解决方案可以使用memcpy 将参数从堆栈复制到 用于检查或存储的数据存储器 如果有帮助的话
  • 如果ds=ss,您可以使用&来查找 从中传递的参数的地址 内部函数(¶m1和¶m2)
  • 如果ds和ss不相等(如 可能是多线程的 应用程序)您将需要一个 使用“far”的memcpy变体 寻址“哪个将处理 ds和ss不同的情况

在您的情况下,提取当前和以前的堆栈帧指针(即bp寄存器)是可能的,但可能不是完全有用的,并使用标准堆栈帧结构确定有多少个4字节(对于32位应用程序)在调用当前例程时已传递参数单位。您将无法确定哪些单位是字符、短单位或长单位,以及它们中的两个单位是否可能是长/长参数


我想了更多。考虑一个典型的函数调用“FUNC(A,B)”。调用代码除非在寄存器中有参数(一些X8632编译器选项和英特尔建议的X8664),否则代码会变成这样的

               ; long *esp,*ebp;
push b         ; *(--esp)=b;
push a         ; *(--esp)=a;
call func      ; *(--esp)=return_address_location;
return_address_location:
add esp,8      ; esp+=2;    // free memory allocated for passing parameters
然后,您将使用func进行处理

func:
push ebp       ; *(--esp)=(long) ebp;    // save current ebp <=> current stack frame 
mov ebp,esp    ; ebp=esp;                // create new stack frame in ebp
sub esp,16     ; esp-=4;                 // reserve space for local variables <=> sizeof(long)*4

(func code ...)
func:
按ebp;*(-esp)=(长)ebp;//保存当前ebp当前堆栈帧
mov ebp,esp;ebp=esp;//在ebp中创建新堆栈帧
子esp,16;esp-=4;//为局部变量sizeof(长)*4保留空间
(职能代码…)
现在,当您在func中,需要访问参数时,可以使用ebp+2和ebp+3(*ebp包含以前的ebp,ebp+1返回