user-0 提问: 一段程序,32位windows下执行可以,64位下总会出错

回复:
user: user-1
content: 看来的确是DEP的事

user: user-2
content: 引用 11 楼 xuch318 的回复:自己解决了,用VirtualAlloc ,具体的原理还不怎么明白,不过可以运行了,楼上的各位,谢谢了,不过请你们下次回答问题时看清我主要问的是什么.下面顺带的把我上面提问的代码完善些,不过没有最终完善 #include <stdio.h>  int ss(int a, int b, int c) { return a+b+c; }  int main() {   long a;   const unsigned char t[] =  #if defined(WIN32) #if defined(__x86_64)  {0x55, 0x48, 0x89, 0xe5, 0x89, 0x4d, 0x10, 0x89, 0x55, 0x18, 0x44, 0x89, 0x45, 0x20, 0x8b, 0x45, 0x18, 0x8b, 0x55, 0x10, 0x01, 0xc2, 0x8b, 0x45, 0x20, 0x01, 0xd0, 0x5d, 0xc3}; #else   {0x55, 0x89, 0xe5, 0x8b, 0x45, 0x0c, 0x8b, 0x55, 0x08, 0x01, 0xd0, 0x03, 0x45, 0x10, 0x5d, 0xc3}; #endif #endif   printf("%s\n", t);  // 1   int (*x)(int, int ,int );   x = (int(*)(int,int,int))t;   a = x(1,2,8);  // 2   printf("%ld\n", a);   return 1; }   这么看不会再有人说我的t是32位或者64位汇编了吧?还有,我主要提问是在 "// 2"那句会出错,不再上面"// 1",即使说编译器没在最后加0x00,但那么大内存肯定有,到时候结束就是了,我写这句是说内存可以访问,但不可执行的 你说的是用VirtualAlloc来分配t数组？还是怎么的？

user: user-0
content: 自己解决了,用VirtualAlloc ,具体的原理还不怎么明白,不过可以运行了,楼上的各位,谢谢了,不过请你们下次回答问题时看清我主要问的是什么.下面顺带的把我上面提问的代码完善些,不过没有最终完善 #include <stdio.h>  int ss(int a, int b, int c) { return a+b+c; }  int main() {   long a;   const unsigned char t[] =  #if defined(WIN32) #if defined(__x86_64)  {0x55, 0x48, 0x89, 0xe5, 0x89, 0x4d, 0x10, 0x89, 0x55, 0x18, 0x44, 0x89, 0x45, 0x20, 0x8b, 0x45, 0x18, 0x8b, 0x55, 0x10, 0x01, 0xc2, 0x8b, 0x45, 0x20, 0x01, 0xd0, 0x5d, 0xc3}; #else   {0x55, 0x89, 0xe5, 0x8b, 0x45, 0x0c, 0x8b, 0x55, 0x08, 0x01, 0xd0, 0x03, 0x45, 0x10, 0x5d, 0xc3}; #endif #endif   printf("%s\n", t);  // 1   int (*x)(int, int ,int );   x = (int(*)(int,int,int))t;   a = x(1,2,8);  // 2   printf("%ld\n", a);   return 1; }   这么看不会再有人说我的t是32位或者64位汇编了吧?还有,我主要提问是在 "// 2"那句会出错,不再上面"// 1",即使说编译器没在最后加0x00,但那么大内存肯定有,到时候结束就是了,我写这句是说内存可以访问,但不可执行的

user: user-3
content: 计算机组成原理→DOS命令→汇编语言→C语言（不包括C++）、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言（包括C++）、架构……  对学习编程者的忠告： 眼过千遍不如手过一遍！ 书看千行不如手敲一行！ 手敲千行不如单步一行！ 单步源代码千行不如单步对应汇编一行！  VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。 对VC来说，所谓‘调试时’就是编译连接通过以后，按F10或F11键单步执行一步以后的时候，或者在某行按F9设了断点后按F5执行停在该断点处的时候。 （Turbo C或Borland C用Turbo Debugger调试,Linux或Unix下用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。）

user: user-0
content: 引用 8 楼 bigbaldy 的回复:t里面是32位汇编，64bit下肯定执行不了 你觉得我在后面说转成32位编译器要改下t的值是什么意思？

user: user-1
content: t里面是32位汇编，64bit下肯定执行不了

user: user-2
content: 引用 3 楼 xuch318 的回复:[quote=引用 1 楼 xiejianjun417 的回复:] 首先printf("%s\n", t);这一句就已经导致错误了，你采用%s格式来打印，就已经非法访问了。%s会打印直到发现‘\0'的结束符，t是一个字符数组，但是不是一个字符串。 再者x = (int(*)(int,int,int))t;怎么能直接将一个数组强制转换成函数指针呢？这样调用，肯定出问题呀  语言允许,请不要用正常思维来想这段程序,知道溢出怎么回事就不会对这段程序感觉奇怪了 这段程序从语法来说没什么问题,我打印那段字符也不是为了看printf的对错,只是看t所在的内存能否访问,而且我这么初始化内存,最后一个位编译器会加上'\0'字符的[/quote] 真是高端，还有这样的编译器

user: user-0
content: 引用 5 楼 zhao4zhong1 的回复:t的值只对应32位汇编指令码而不对应64位汇编指令码。 能说的详细点吗?怎么不对应64位的汇编指令呢?

user: user-3
content: t的值只对应32位汇编指令码而不对应64位汇编指令码。

user: user-0
content: 引用 楼主 xuch318 的回复:程序如下,win764位下执行到a=x(1,2,8)时就会出错,该程序在32位能够执行(t值已经更新,表示的是ss编译后的二进制),编译器用的是64位的gcc 程序执行到 "// 1"处是没问题的,看来内存是可以访问的,只是到"// 2"处就出错,看来该段内存有读的权限,但好像没运行的权限 前段时间在64位linux上也碰到类似问题,后来高人指点mprotect来解决,windows 64位下是不是问题类似?请问需要调用什么函数?  t后的数值没错,请有怀疑的看官试试自己生成.  #include <stdio.h>  int ss(int a, int b, int c) { return a+b+c; }  int main() {   long a;   unsigned char t[] = {0x55, 0x48, 0x89, 0xe5, 0x89, 0x4d, 0x10, 0x89, 0x55, 0x18, 0x44, 0x89, 0x45, 0x20, 0x8b, 0x45, 0x18, 0x8b, 0x55, 0x10, 0x01, 0xc2, 0x8b, 0x45, 0x20, 0x01, 0xd0, 0x5d, 0xc3};   printf("%s\n", t);  // 1   int (*x)(int, int ,int );   x = (int(*)(int,int,int))t;   a = x(1,2,8);  // 2   printf("%ld\n", a);   return 1; }   相信大家好多人没有64位的mingw,我用的是TDM-GCC-64,sourceforge的一个项目,大家可以下下来看看帮我分析下  这段程序32位windows下可以执行,不过要t[] = {0x55, 0x89, 0xe5, 0x8b, 0x45, 0x0c, 0x8b, 0x55, 0x08, 0x01, 0xd0, 0x03, 0x45, 0x10, 0x5d, 0xc3}, gcc -o x x.c编译(x是你所起的文件名)

user: user-0
content: 引用 1 楼 xiejianjun417 的回复:首先printf("%s\n", t);这一句就已经导致错误了，你采用%s格式来打印，就已经非法访问了。%s会打印直到发现‘\0'的结束符，t是一个字符数组，但是不是一个字符串。 再者x = (int(*)(int,int,int))t;怎么能直接将一个数组强制转换成函数指针呢？这样调用，肯定出问题呀  语言允许,请不要用正常思维来想这段程序,知道溢出怎么回事就不会对这段程序感觉奇怪了 这段程序从语法来说没什么问题,我打印那段字符也不是为了看printf的对错,只是看t所在的内存能否访问,而且我这么初始化内存,最后一个位编译器会加上'\0'字符的

user: user-4
content: 引用 1 楼 xiejianjun417 的回复:首先printf("%s\n", t);这一句就已经导致错误了，你采用%s格式来打印，就已经非法访问了。%s会打印直到发现‘\0'的结束符，t是一个字符数组，但是不是一个字符串。 再者x = (int(*)(int,int,int))t;怎么能直接将一个数组强制转换成函数指针呢？这样调用，肯定出问题呀  很明白了....

user: user-2
content: 首先printf("%s\n", t);这一句就已经导致错误了，你采用%s格式来打印，就已经非法访问了。%s会打印直到发现‘\0'的结束符，t是一个字符数组，但是不是一个字符串。 再者x = (int(*)(int,int,int))t;怎么能直接将一个数组强制转换成函数指针呢？这样调用，肯定出问题呀