c********0 发帖数: 26 | 1 embedded systems engineer
Q: in memory, the starting address of a c function is 0x400000. How can you
write another piece of c code to make a jump to that address?
不知道该怎么回答。 |
f*******t 发帖数: 7549 | 2 _asm jmp 0x400000;
行不?我瞎扯的…… |
c******e 发帖数: 545 | 3 really easy:
void (*func_ptr)(void) = (void (*)())0x400000;
func_ptr(); |
c******e 发帖数: 545 | 4 no.
1. _asm ... is architecture dependent
2. jmp does not push return address on stack
【在 f*******t 的大作中提到】 : _asm jmp 0x400000; : 行不?我瞎扯的……
|
a********m 发帖数: 15480 | |
a********m 发帖数: 15480 | 6 恩。还有先问好参数情况。
【在 c******e 的大作中提到】 : really easy: : void (*func_ptr)(void) = (void (*)())0x400000; : func_ptr();
|
c******e 发帖数: 545 | 7 要是带参数的情况就复杂多了,在传统x86平台上,会涉及至少三个问题:
1. 参数传递的方式:stack(__stdcall,__pascal,__cdecl),register+stack(__
fastcall)
2. 参数传递的顺序:右到左(__cdecl,__stdcall),左到右(__pascal),不定,取
决于compiler(__fastcall)
3. 处理stack:主函数(__cdecl),被叫函数(其他)
如果不特殊说明,函数的calling convention都是默认__cdecl,windows平台上API默
认__stdcall(除了变参函数,这个只有__cdecl可以处理)
这些应该都是比较古老的知识了,现在可能除了搞底层的人都不去管了,从前主要用在
函数库互调和写能被c调用的汇编函数的时候用的。
轻量级嵌入式平台上情况还不一样,主要因为资源有限,一些平台上根本没有参数栈,
函数参数都是保存在全局变量里的,函数本身默认为不可重入。这种情况再声明函数指
针的时候要指明是可重入函数(一般compiler会有特殊的keyword),当然被叫函数也
应该是相同定义。
总体上我觉得你把可能性都说了就足够了,应该是考察对底层的了解。
【在 a********m 的大作中提到】 : 恩。还有先问好参数情况。
|
c****p 发帖数: 6474 | 8 mark
【在 c******e 的大作中提到】 : 要是带参数的情况就复杂多了,在传统x86平台上,会涉及至少三个问题: : 1. 参数传递的方式:stack(__stdcall,__pascal,__cdecl),register+stack(__ : fastcall) : 2. 参数传递的顺序:右到左(__cdecl,__stdcall),左到右(__pascal),不定,取 : 决于compiler(__fastcall) : 3. 处理stack:主函数(__cdecl),被叫函数(其他) : 如果不特殊说明,函数的calling convention都是默认__cdecl,windows平台上API默 : 认__stdcall(除了变参函数,这个只有__cdecl可以处理) : 这些应该都是比较古老的知识了,现在可能除了搞底层的人都不去管了,从前主要用在 : 函数库互调和写能被c调用的汇编函数的时候用的。
|
c*********t 发帖数: 2921 | 9 thanks.
【在 c******e 的大作中提到】 : 要是带参数的情况就复杂多了,在传统x86平台上,会涉及至少三个问题: : 1. 参数传递的方式:stack(__stdcall,__pascal,__cdecl),register+stack(__ : fastcall) : 2. 参数传递的顺序:右到左(__cdecl,__stdcall),左到右(__pascal),不定,取 : 决于compiler(__fastcall) : 3. 处理stack:主函数(__cdecl),被叫函数(其他) : 如果不特殊说明,函数的calling convention都是默认__cdecl,windows平台上API默 : 认__stdcall(除了变参函数,这个只有__cdecl可以处理) : 这些应该都是比较古老的知识了,现在可能除了搞底层的人都不去管了,从前主要用在 : 函数库互调和写能被c调用的汇编函数的时候用的。
|
a********m 发帖数: 15480 | 10 声明函数指针变量的时候写好参数就可以了吧。如果需要字节解决参数传递/压栈就太
复杂了,而且也失去了可移植性。
【在 c******e 的大作中提到】 : 要是带参数的情况就复杂多了,在传统x86平台上,会涉及至少三个问题: : 1. 参数传递的方式:stack(__stdcall,__pascal,__cdecl),register+stack(__ : fastcall) : 2. 参数传递的顺序:右到左(__cdecl,__stdcall),左到右(__pascal),不定,取 : 决于compiler(__fastcall) : 3. 处理stack:主函数(__cdecl),被叫函数(其他) : 如果不特殊说明,函数的calling convention都是默认__cdecl,windows平台上API默 : 认__stdcall(除了变参函数,这个只有__cdecl可以处理) : 这些应该都是比较古老的知识了,现在可能除了搞底层的人都不去管了,从前主要用在 : 函数库互调和写能被c调用的汇编函数的时候用的。
|
c******e 发帖数: 545 | 11 打个比方说,地址在0x400000的函数当初是用__stdcall修饰的(比如win32平台上的
WINAPI宏,API函数默认修饰),那么声明指针的时候也要用相同修饰:
void (__stdcall*func)(int,int) = (void (__stdcall*)(int,int))0x400000;
func(10,100);
如果用系统默认__cdecl的话
void (*func)(int,int) = (void (*)(int,int))0x400000;
func(10,100);
生成的调用代码就完全不正确,原因见原帖。这种问题平时是见不到的,因为compiler
会核对原型,而且link的时候因为name mangling也通不过,但是因为指针强制赋值,
所以跳过了所有的检查,需要自己确定才行。
【在 a********m 的大作中提到】 : 声明函数指针变量的时候写好参数就可以了吧。如果需要字节解决参数传递/压栈就太 : 复杂了,而且也失去了可移植性。
|
a********m 发帖数: 15480 | 12 en. compiling/linking setting need to be the same.
compiler
【在 c******e 的大作中提到】 : 打个比方说,地址在0x400000的函数当初是用__stdcall修饰的(比如win32平台上的 : WINAPI宏,API函数默认修饰),那么声明指针的时候也要用相同修饰: : void (__stdcall*func)(int,int) = (void (__stdcall*)(int,int))0x400000; : func(10,100); : 如果用系统默认__cdecl的话 : void (*func)(int,int) = (void (*)(int,int))0x400000; : func(10,100); : 生成的调用代码就完全不正确,原因见原帖。这种问题平时是见不到的,因为compiler : 会核对原型,而且link的时候因为name mangling也通不过,但是因为指针强制赋值, : 所以跳过了所有的检查,需要自己确定才行。
|
c********0 发帖数: 26 | |