M$VC如何生成位置无关代码(-fpic)

mLee79 2011-06-25 01:28:02
加精
gcc 系列好像都很简单, 不知道最新的M$VC有这个选项没....

比如这样子:
#include <stdio.h>

int main()
{
#ifdef __i386__
((void(*)( int(*)(const char*)))(
"\x55\x89\xE5\x53\xE8\x1B\x00\x00\x00\x81\xC3\x77\x7F\xFB\xF7\x83"
"\xEC\x14\x8D\x83\xA8\x80\x04\x08\x89\x04\x24\xFF\x55\x08\x83\xC4"
"\x14\x5B\x5D\xC3\x8B\x1C\x24\xC3\x48\x65\x6C\x6C\x6F\x20\x57\x6F"
"\x72\x6C\x64\x21\x00"))( puts );
#elif defined( __arm_le__ )
((void(*)( int(*)(const char*)))(
"\x08\x40\x2D\xE9\x00\x30\xA0\xE1\x10\x00\x9F\xE5\x00\x00\x8F\xE0"
"\x0F\xE0\xA0\xE1\x13\xFF\x2F\xE1\x08\x40\xBD\xE8\x1E\xFF\x2F\xE1"
"\x10\x00\x00\x00\x48\x65\x6C\x6C\x6F\x20\x57\x6F\x72\x6C\x64\x21"
"\x00\x00\x00\x00"))( puts );
#endif

return 0;
}
-----------------------------------------------------------------
shell code 是这样子生成的:
void foobar( void(*fun)(char*) )
{
fun( "Hello World!" );
}
gcc -m32 -O3 1.c -c -fpic ; ld -melf_i386 -e foobar 1.o -o 1.elf ; objcopy -O binary 1.elf 1.bin
arm-none-eabi-gcc -O3 -c 1.c -fpic ; arm-none-eabi-ld -e foobar 1.o -o 1.elf ; arm-none-eabi-objcopy.exe -O binary 1.elf 1.bin
-----------------------------------------------------------------
难道我生成在M$VC跑的程序也要用gcc生成代码么, 没天理啊...



...全文
2047 92 打赏 收藏 转发到动态 举报
写回复
用AI写文章
92 条回复
切换为时间正序
请发表友善的回复…
发表回复
大道曙光 2011-06-30
  • 打赏
  • 举报
回复
俺是来学习的
mLee79 2011-06-29
  • 打赏
  • 举报
回复
[Quote=引用 87 楼 pengzhixi 的回复:]

vs只编译一个源文件的时候就会生成位置无关代码么?
[/Quote]
我试了一下, 应该是的, 因为我编译了个不算太小的工程, 大概包括500行的代码, 最终结果没有任何重定位项 .....

不过还得受的一点限制是, 不能使用任何全局性质变量, 这个在 gcc 下则没有这个限制...
pengzhixi 2011-06-29
  • 打赏
  • 举报
回复
vs只编译一个源文件的时候就会生成位置无关代码么?
mLee79 2011-06-29
  • 打赏
  • 举报
回复
M$VC下找到一个不是办法的办法就是把所有的源代码include到一个文件中编译... 虽然有点限制条件, 不过跟其他限制条件比起来这算不上啥... 即使是 gcc 也最好这样做, 这样生成的代码质量比分离编译好的多....

顺便附上个 x86 下一个TEA加密略微变形的代码, 它会作为一个源代码加密项目的一部分...
现在 对称加密/散列/随机数发生器 都好了, 今天开始写 PKCS 部分...

现在有结果了, 等几天结贴吧....

#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <time.h>

struct XSLCSE_ENCRYPT_param
{
int X_Encrypt;
int X_Key [16/sizeof(int)];
int X_data[16/sizeof(int)];
};

void binCryptography( int enc , const void* key /* size_is(16) */, const void* input /* size_is(16) */ , void* output /* size_is(16) */ )
{
struct XSLCSE_ENCRYPT_param param;
static const char* const svc =
"\x11Hello BIN World!"
"\x55\x57\x56\x83\xEC\x18\x8B\x54\x24\x2C\x8B\x44\x24\x2C\x8B\x0A"
"\x83\xC0\x14\x89\x44\x24\x0C\x85\xC9\x0F\x85\x19\x01\x00\x00\x8B"
"\x72\x14\x89\xD0\x83\xC2\x18\x89\x54\x24\x14\x8B\x50\x18\xBF\x20"
"\x37\xEF\xC6\x8B\x40\x04\x89\x04\x24\x8B\x44\x24\x2C\x8B\x40\x08"
"\x89\x44\x24\x04\x8B\x44\x24\x2C\x8B\x40\x0C\x89\x44\x24\x08\x8B"
"\x44\x24\x2C\x8B\x48\x10\x66\x90\x89\xF0\x89\xF5\xC1\xE0\x04\x03"
"\x44\x24\x08\xC1\xED\x05\x01\xCD\x31\xE8\x8D\x2C\x37\x31\xE8\x29"
"\xC2\x89\xD0\x89\xD5\xC1\xE0\x04\xC1\xED\x05\x03\x04\x24\x03\x6C"
"\x24\x04\x31\xE8\x8D\x2C\x3A\x31\xE8\x29\xC6\x81\xC7\x47\x86\xC8"
"\x61\x75\xC5\x8B\x44\x24\x2C\xBF\x20\x37\xEF\xC6\x89\x50\x18\x8B"
"\x54\x24\x0C\x89\x70\x14\x8B\x44\x24\x0C\x83\xC2\x08\x89\x54\x24"
"\x10\x8B\x70\x08\x8B\x50\x0C\x90\x89\xF0\x89\xF5\xC1\xE0\x04\x03"
"\x44\x24\x08\xC1\xED\x05\x01\xCD\x31\xE8\x8D\x2C\x37\x31\xE8\x29"
"\xC2\x89\xD0\x89\xD5\xC1\xE0\x04\xC1\xED\x05\x03\x04\x24\x03\x6C"
"\x24\x04\x31\xE8\x8D\x2C\x3A\x31\xE8\x29\xC6\x81\xC7\x47\x86\xC8"
"\x61\x75\xC5\x8B\x44\x24\x0C\x89\x50\x0C\x8B\x54\x24\x2C\x89\x70"
"\x08\x8B\x42\x14\x8B\x54\x24\x10\x29\x02\x8B\x54\x24\x2C\x8B\x42"
"\x18\x8B\x54\x24\x0C\x29\x42\x0C\x8B\x44\x24\x14\x81\x2A\x82\x6B"
"\x15\x6A\x81\x00\x74\xC5\x3A\x28\x83\xC4\x18\x31\xC0\x5E\x5F\x5D"
"\xC3\x8D\xB4\x26\x00\x00\x00\x00\x81\x00\x82\x6B\x15\x6A\x31\xFF"
"\x81\x6A\x18\x74\xC5\x3A\x28\x83\xC2\x1C\x89\x54\x24\x0C\x8B\x54"
"\x24\x2C\x8B\x42\x14\x8B\x54\x24\x0C\x01\x02\x8B\x54\x24\x2C\x8B"
"\x42\x18\x01\x42\x20\x89\xD0\x8B\x40\x04\x8B\x72\x14\x8B\x52\x18"
"\x89\x04\x24\x8B\x44\x24\x2C\x8B\x40\x08\x89\x44\x24\x04\x8B\x44"
"\x24\x2C\x8B\x40\x0C\x89\x44\x24\x08\x8B\x44\x24\x2C\x8B\x48\x10"
"\x89\xD5\x81\xEF\x47\x86\xC8\x61\xC1\xE5\x04\x03\x2C\x24\x8D\x04"
"\x17\x31\xE8\x89\xD5\xC1\xED\x05\x03\x6C\x24\x04\x31\xE8\x01\xC6"
"\x89\xF0\x89\xF5\xC1\xE0\x04\x03\x44\x24\x08\xC1\xED\x05\x01\xCD"
"\x31\xE8\x8D\x2C\x3E\x31\xE8\x01\xC2\x81\xFF\x20\x37\xEF\xC6\x75"
"\xBF\x8B\x44\x24\x2C\x31\xFF\x89\x70\x14\x8B\x70\x1C\x89\x50\x18"
"\x8B\x44\x24\x0C\x8B\x50\x04\x90\x89\xD5\x81\xEF\x47\x86\xC8\x61"
"\xC1\xE5\x04\x03\x2C\x24\x8D\x04\x17\x31\xE8\x89\xD5\xC1\xED\x05"
"\x03\x6C\x24\x04\x31\xE8\x01\xC6\x89\xF0\x89\xF5\xC1\xE0\x04\x03"
"\x44\x24\x08\xC1\xED\x05\x01\xCD\x31\xE8\x8D\x2C\x3E\x31\xE8\x01"
"\xC2\x81\xFF\x20\x37\xEF\xC6\x75\xBF\x8B\x44\x24\x2C\x89\x70\x1C"
"\x8B\x44\x24\x0C\x89\x50\x04\x83\xC4\x18\x31\xC0\x5E\x5F\x5D\xC3"
;
param.X_Encrypt = enc;
memcpy( ¶m.X_data , input , 16 );
memcpy( ¶m.X_Key , key , 16 );
(*(void(*)(const void*const,void*))(svc+svc[0]))( svc , ¶m );
memcpy( output , ¶m.X_data , 16 );
}

int main()
{
int i , r;
char key[16];
int plain[16/sizeof(int)] , cipher[16/sizeof(int)] , verify[16/sizeof(int)];

srand( time(NULL) );
for( i = 0; i < 16; ++i )
key[i] = (char)rand();

for( r = 0; r < 100000; ++r )
{
for( i = 0; i < sizeof( plain ) / sizeof(plain[0] ); ++i )
plain[i] = (rand() << 16)+rand();

binCryptography( 1 , key , plain , cipher );
binCryptography( 0 , key , cipher , verify );

if( memcmp( plain , verify , 16 ) != 0 )
printf( "error" );
}

return 0;
}
clever101 2011-06-29
  • 打赏
  • 举报
回复
在网上下载了一篇《VC命名行编译C++》,其中一段提到:

/QIPF_noPIC(生成依赖于位置的代码)
默认情况下,面向 Itanium 的 Visual C++ 编译器会生成与位置无关的代码。

/QIPF_noPIC 将生成具有位置相关代码的映像。

/QIPF_noPIC 只可用于面向 Itanium 的编译器。在面向 x64 或 x86 的编译器中,此编译器选项不可用。如果映像无法在其首选地址加载,由于在首选地址之外的其他地址加载映像时,与位置无关的代码中的相对地址不需要进行修正,所以与位置无关的代码比位置相关代码加载得更快。而且,Windows 还允许用户共享未修正过的相同代码,而对于已修正代码,每个用户将获得已修正代码的单独实例。

但是,如果映像无法在首选地址加载,则与位置无关的代码的性能比位置相关代码的性能差。以服务器应用程序为例,其中用户可能并不在乎(可能)启动时间较长,且用户很少同时运行这些应用程序的多个副本,则此应用程序可从位置相关代码所提供的额外性能中受益。
mLee79 2011-06-29
  • 打赏
  • 举报
回复
唉, 要M$改还不如主动适应它,实际上这个限制是很好地,能大大提高gcc代码生成的质量,按M$VC的要求去编写代码, 这样我在gcc编译是即使不加 -fpic 也照样生成 pic 代码... 反正我工作中是不需要M$VC地, 虽然偶95%以上的代码都是在M$VC中编写的(中毒太深啊,vim啥的实在是来不及再去学了), 它不支持就算了....

xunxun 2011-06-29
  • 打赏
  • 举报
回复
这个贴好火,lz可以到msdn上强烈建议微软加入此功能
mLee79 2011-06-27
  • 打赏
  • 举报
回复
现在是不大放心啊, 转前先拖到 IDA 里看下重定位表. 该自己写个代码检查有不合适的重定位信息了....
redleaves 2011-06-27
  • 打赏
  • 举报
回复
[Quote=引用 77 楼 mlee79 的回复:]为虾米 Intel 设计 x86 指令集的时候让 pc 不能作为基址寻址, 不然就没这些麻烦了...[/Quote]你看下x86指令的格式就知道了,x86提供的寻址类型太多.已经没地方放这些功能了.而且x86有历史包袱,用了很多单字节指令. 相比之下,ARM的指令就规整得多,看上去也很漂亮,而且它那些前加/后加的机制也很灵活.但却苦了写汇编和写编译器的人.
其实x86给寄存器分配了固定用处,虽然限制了灵活性,但用起来简单.不像ARM,随时都搞不清楚寄存器的用处...
redleaves 2011-06-27
  • 打赏
  • 举报
回复
[Quote=引用 75 楼 mlee79 的回复:]可以重定位的代码跟位置无关的完全不一样吧, 位置无关的我把代码拷贝到不同的位置是可以直接运行的, 可以重定位的代码还得做一次重定位...[/Quote]嗯,但"位置无关"那个名字起的不太好.位置无关代码应该是说,代码可以放到任意位置执行.而重定位就可以实现这个目标.这应该是和固定位置代码相对的.
如果改成 无重定位的位置无关代码 就清楚多了.

抠字眼了...^_^

另外,fpic不能保证一定生成位置无关代码,能这么放心的得用嘛?
mLee79 2011-06-27
  • 打赏
  • 举报
回复
为虾米 Intel 设计 x86 指令集的时候让 pc 不能作为基址寻址, 不然就没这些麻烦了...

lmc158 2011-06-27
  • 打赏
  • 举报
回复
shell code 是这样子生成的:
void foobar( void(*fun)(char*) )
{
fun( "Hello World!" );
}
gcc -m32 -O3 1.c -c -fpic ; ld -melf_i386 -e foobar 1.o -o 1.elf ; objcopy -O binary 1.elf 1.bin
arm-none-eabi-gcc -O3 -c 1.c -fpic ; arm-none-eabi-ld -e foobar 1.o -o 1.elf ; arm-none-eabi-objcopy.exe -O binary 1.elf 1.bin
-----------------------------------------------------------------
难道我生成在M$VC跑的程序也要用gcc生成代码么, 没天理啊...


mLee79 2011-06-27
  • 打赏
  • 举报
回复
[Quote=引用 74 楼 redleaves 的回复:]

引用 68 楼 mlee79 的回复:好像RISC的机器上一般都是生成pic代码, i386太畸形了, vc给 arm , ppc 啥做的应该也是 pic的吧...pic和指令集应该一点关系都没有吧?
而且对于位置无关我一直有点疑问...
如果生成的目标代码完全不要重定位就能执行,这算是位置无关了吧...
但如果生成的目标代码可以重定位.按理说这在一定程度上也算是位置无关了呀.毕竟它不需要……
[/Quote]
本来是没啥关系, 不过生成 pic 代码在 x86 机器上要占用一个寄存器, 大部分情况下还得占用像 bx , si , di 这样的寄存器, 并且每个函数要多一条指令, M$反正没这需求, 也就华丽的忽略掉了三...

可以重定位的代码跟位置无关的完全不一样吧, 位置无关的我把代码拷贝到不同的位置是可以直接运行的, 可以重定位的代码还得做一次重定位...

redleaves 2011-06-27
  • 打赏
  • 举报
回复
[Quote=引用 68 楼 mlee79 的回复:]好像RISC的机器上一般都是生成pic代码, i386太畸形了, vc给 arm , ppc 啥做的应该也是 pic的吧...[/Quote]pic和指令集应该一点关系都没有吧?
而且对于位置无关我一直有点疑问...
如果生成的目标代码完全不要重定位就能执行,这算是位置无关了吧...
但如果生成的目标代码可以重定位.按理说这在一定程度上也算是位置无关了呀.毕竟它不需要在固定位置上加载...
而且就算用gcc -fpic还是不能保证生成的代码完全都是位置无关的...
所以,还是自己做个自动重定位的加载程序最保险.
mLee79 2011-06-27
  • 打赏
  • 举报
回复
[Quote=引用 72 楼 redleaves 的回复:]

引用 71 楼 mlee79 的回复:应该是M$总是使用PE格式, 反正PE格式带着重定位信息, 位置有关无关无所谓...
gcc却要照顾各种各样的格式, elf , a.out , bin 都要, 如果都是生成 elf 那就无所谓了, 如果是其他的不支持重定位的格式, 位置无关就很重要了...位置无关也不过是能自动重定位罢了.不可能所有代码都是绝对的位置无关代码.你干脆自己搞个重定位程序,加……
[/Quote]

gcc 很容易做到完全的位置无关, 只要让导入表为空大部分都可以了...
而M$VC要生成完全的位置无关代码, 写代码的每个地方都要注意...
既然gcc能够很容易的做到位置无关代码, 我显然就不需要弄个M$VC的重定位程序了, 直接用gcc生成然后在VC里运行就行了... 只是这样让我感觉很怪异....


redleaves 2011-06-27
  • 打赏
  • 举报
回复
[Quote=引用 71 楼 mlee79 的回复:]应该是M$总是使用PE格式, 反正PE格式带着重定位信息, 位置有关无关无所谓...
gcc却要照顾各种各样的格式, elf , a.out , bin 都要, 如果都是生成 elf 那就无所谓了, 如果是其他的不支持重定位的格式, 位置无关就很重要了...[/Quote]位置无关也不过是能自动重定位罢了.不可能所有代码都是绝对的位置无关代码.你干脆自己搞个重定位程序,加载后自动把代码重定位一下不就得了.
其实,VC编译的单个编译单元内的代码,很多都可以做到位置无关的.我以前研究内核的时候,那些测试代码都是用VC编译的.自己只要写几个小工具就OK了.
Yeah 2011-06-27
  • 打赏
  • 举报
回复
位置相关也没关系吧 用汇编重定位下
call label1
label1: pop eax
sub eax, offset label1
add eax, xxxxxxxx要重定位的值
mLee79 2011-06-27
  • 打赏
  • 举报
回复
应该是M$总是使用PE格式, 反正PE格式带着重定位信息, 位置有关无关无所谓...
gcc却要照顾各种各样的格式, elf , a.out , bin 都要, 如果都是生成 elf 那就无所谓了, 如果是其他的不支持重定位的格式, 位置无关就很重要了...


pengzhixi 2011-06-27
  • 打赏
  • 举报
回复
难道是vc想追求那点性能所以....
pengzhixi 2011-06-27
  • 打赏
  • 举报
回复
应该不是因为CPU指令集类型的缘故吧?没理由 gcc可以做到,vc做不到啊。
加载更多回复(66)

3,881

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 其它技术问题
社区管理员
  • 其它技术问题社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧