求《一个苦逼的普通人》作者对主角充满恶意书包网:minifox全文

32位未修改源码与修改版的代码下载:
clone :youzhonghui/MiniCRT.git
MiniCRT 64位 linux 系统移植记录
MiniCRT是《程序员的自我修养:链接,转载于库》的作者俞甲子写的小型的C运行时库。里面提供了printf,malloc,free,fopen等比较常用的函数实现。
之所以要捣鼓这个东西,是因为要自己写一个链接器,链接标准库的时候出了麻烦,一些符号在整个libc中都找不到定义,标准库又太大,研究源码,翻文档都不方便,不如拿一个小巧可用的MiniCRT过来,源码在手,知根知底。
但是也不是一帆风顺,我现在用的系统是64位的archlinux,俞甲子在写书的时候用的还是32位系统。搬运到64位系统上还遇上写麻烦,但是比较64位是趋势了,不能老窝在32位里,在前人经验的庇护下学习吧。所以捣騰了一天,修改了源码,把他移植到64位的linux系统上来,这个过程也学到一些有趣的东西。下面是过程记录。
下了源码,按照readme.txt编译代码
gcc -c -fno-builtin -nostdlib entry.c malloc.c stdio.c string.c printf.c
ar -rs minicrt.a malloc.o printf.o stdio.o string.o
gcc -c -ggdb -fno-builtin -nostdlib test.c
ld -static -e mini_crt_entry entry.o test.o minicrt.a -o test
但是在第一句的时候,entry.c就无法通过编译。错误信息:
entry.c:59:
Error: unsupported instruction `mov'
打开发现错在一句内联汇编上:
%%ebp,%0 \n&:&=r&(ebp_reg));
我学汇编写汇编都是在windows下,对AT&T的汇编语法不熟,谷歌之,找到一篇好资料:
语法上这句汇编没错,我也是在几次试验以后猛然发现指针竟然是64位的。我这才意识到我真的是在64位系统上阿(你特么不是一直在用吗 – -)。那么错误很明显了,movl 和 ebp是32位的,%0即ebp_reg是64位的。
%%rbp,%0 \n&:&=r&(ebp_reg));
编译通过。
下面一堆警告,还是64位指针惹的祸。
将所有源文件中的int换成了long,main函数的int返回类型可以保留,再编译,警告消失。
但是运行./test
意料之外,无输出。
把test.c换成了一个更简单的文件来debug
&minicrt.h&
int&main()
&&&&&&&&printf(&hello
world\n&);
&&&&&&&&return&0;
单步跟踪发现,int 0×80的4号中断不好使了。网上也没找到相关的信息。
我和小伙伴们都有点心灰意冷(要是64位系统不支持这个4号中断,我还搞个蛋啊!)
但是在一股不甘心的力量驱动下,又做了几次试验,把这段代码独立出来,编成32位,运行,惊奇发现,输出hello world了。
那么64位系统还是支持这个系统调用的,为什么32位可以,而64位不行?
这个中断只能输出4GB以内地址的字符串,也就是支持ecx,但是不支持rcx。
验证的试验很容易做,发现确是是这样。
readelf -s test
一看,全局变量,静态变亮的地址都在 0×400000 – 0x60FFFFF 之内。那么能越界的就是栈中的局部变量了。
那么我必须要在调用4号中断之前,把栈里的内容拷贝到全局变量中,然后把全局变量指针交给4号中断,这样就解决越界的问题了。
修改了fputc和fputs函数:
static&char&__fputc_tmp_val__
long&fputc(char&c,FILE*
&&&&&&&&__fputc_tmp_val__
&&&&&&&&if&(fwrite(&__fputc_tmp_val__,1,1,stream)
&&&&&&&&&&&&&&&&return&EOF;
&&&&&&&&else
&&&&&&&&&&&&&&&&return&c;
static&char&__fputs_tmp_array__[256]
static&int&__fputs_tmp_size__
long&fputs(const&char*
str,FILE&*stream)
&&&&&&&&long&len&&&&&&&
= strlen(str);
&&&&&&&&if(
len &= __fputs_tmp_size__ )
&&&&&&&&&&&&&&&&return&EOF;
&&&&&&&&strcpy(
__fputs_tmp_array__,str );
&&&&&&&&if&(fwrite(__fputs_tmp_array__,1,len,stream)
&&&&&&&&&&&&&&&&return&EOF;
&&&&&&&&else
&&&&&&&&&&&&&&&&return&
测试,顺利输出hello world
原以为这样就大功告成了,但是换回原来的tes进入t.c一试,又没有输出。
晕,单步!
发现参数根本没有正确传递。看反汇编:
printf调用之前
printf(&%d
%s\n&,len,buf);
mov -0x10(%rbp),%rdx
mov -0x18(%rbp),%rax
mov %rax,%rsi
mov $0x4015f6,%edi
mov $0x0,%eax
callq 0x400e5b
进入printf
mov %rsp,%rbp
sub $0xd0,%rsp
mov %rsi,-0xa8(%rbp)
mov %rdx,-0xa0(%rbp)
mov %rcx,-0x98(%rbp)
mov %r8,-0x90(%rbp)
mov %r9,-0x88(%rbp)
test %al,%al
je 0x400ead
movaps %xmm0,-0x80(%rbp)
movaps %xmm1,-0x70(%rbp)
movaps %xmm2,-0x60(%rbp)
movaps %xmm3,-0x50(%rbp)
movaps %xmm4,-0x40(%rbp)
movaps %xmm5,-0x30(%rbp)
movaps %xmm6,-0x20(%rbp)
movaps %xmm7,-0x10(%rbp)
mov %rdi,-0xc8(%rbp)
之前写操作系统,也自己实现过printf,但是..但是,这是妹啊!为什么参数没有通过栈传递!
找资料,同时心中默默将gcc骂了十遍。
找到一篇资料:
我从里面摘出比较重要的一段:
「而GCC的调用约定跟VC不同。前6个整数参数会依次放到rdi, rsi, rdx, rcx, r8, r9中,前8个浮点参数放到xmm0到xmm7中。除了使用了更多的寄存器,与vc不同的是,整数和浮点数寄存器是混合使用的不用为没用的参数预留。还是刚才的例子,第一个参数是int,第二个是double,第三个char*,第四个double,参数数会依次放到 rdi,xmm0,rsi,xmm1. 另外,没有在栈上预留寄存器区。 更多的参数和vc一样,放在栈上。」
通过试验发现,通过寄存器传递参数这个设置没办法通过__attribute__((regparm(0)))来关闭。
这样只能修改代码了。
可以看到,要实现一个寄存器参数版的va_start,va_arg,va_end比较麻烦,我又不想修改过多代码。
观察发现,在-O0优化选项下(gcc的默认选项),进入printf后,会先把rsi,rdx…这些寄存器挨个放入栈。如上面所示,不过实际传入的参数个数有多少。
但是比较奇怪的是,应该是rdi为第一个参数,但是rdi并没有出现在rsi之前。
别忘了,printf的第一个参数是显示声明的,是一个字符串,上边汇编的最后一句,mov %rdi,-0xc8(%rbp)就表明正是如此。
那么我们要的参数列表就从rsi开始,它被复制到-0xa8(%rbp)的位置。Check!这就是我们要找的位置。
另外有一点很需要注意的是,浮点参数会放到xmm0到xmm7中,从上面的汇编可以看出,rsi,rdx..xmm0…的排列顺序是固定的。在复制xmm0-xmm7之前,有一句test %al ,%al,当调用printf时,有传入浮点参数时eax=1,否则为0。超过六个的整数参数会被压入栈中。
好了,只要不传入浮点参数,那么我们就可以通过0xa8的偏移来找到arg_list。而MiniCRT的printf也没有支持浮点输出,那么,我们就取巧吧。
将printf由
int&printf(const&char&*format,...)
&&&&&&&&va_list(arglist);
&&&&&&&&va_start(arglist,format);
&&&&&&&&return&vfprintf(stdout,format,arglist);
long&printf(const&char&*format,...)
&&&&&&&&char*
&&&&&&&&asm(
%%rbp,%0&:&=r&(arglist)
&&&&&&&&arglist
&&&&&&&&return&vfprintf(stdout,format,arglist);
好了,再输入readme.txt里的四条命令,运行test,是不是看到输出了?
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:7276次
排名:千里之外
原创:19篇}

我要回帖

更多关于 作者 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信