2008/4

这张图真的还是假的?

今天王冬同学发给我的。哪位如果用搜狗输入法能否帮忙确认一下真假?怎么看也不像PS的啊!(真要是话的说明那人PS水平不低~!)不知道是哪位高人做的?或者是西邮在搜狐有卧底?

assembler的一个hack

如果编译一个relocatable目标文件,你通过反汇编不难发现所有的call指令竟然都是同一个机器码!即:e8 fc ff ff ff。

我们知道,不同的函数有不同的入口,可这里怎么都会用这么一个奇怪的地址呢?

翻一下Intel指令手册,我们很容易就能在3-104 Vol. 2A中找到call指令的各种编码方式。根据这里的opcode为e8我们不难确定这个call是用的下面这种方式:

E8 cd CALL rel32

这就告诉我们,opcode后面其实是一个32位相当的相对地址。如果你肯在往后翻几页的话,就会发现这种方式的执行过程,如下:

tempEIP ←EIP +DEST; ( DEST is rel32 )
IF tempEIP is not within code segment limit THEN #GP(0); FI;
IF stack not large enough for a 4-byte return address
THEN #SS(0); FI;
Push(EIP);
EIP ←tempEIP;

也就是说会用当前的EIP加上那个相对地址作为最终的call转移地址。别慌,还没完,我们继续。

我们知道,relocatable目标文件的符号地址都是不能使用的,因为还没经过linker转化。linker转化后的地址才是最终的地址,也就是说从上面那个地址到最后的地址还有一段过程,由ld来完成。

我们知道,这里正确的地址应该是该符号实际的地址与这个call地址之间的偏移。而这等于这个函数的实际入口与.text section之间的偏移减去这个符号相对.text的偏移!后者由ELF格式直接给出,而前者也很容易计算。

到这里你会发现,不对,我们那个fc ff ff ff还没用上!是,因为我们前面忽视了很重要的一点,EIP是指向下一条指令的而不是当前这条的地址!也就是说,我们前面的结果需要修正!具体说是需要修正一个 -0x4。再看一下fc ff ff ff,不正是-4么?!(x86是little endian!)对,正是这个由assembler故意安排的-4修正了我们call指令!

当然了,如果符号不是一个函数地址,而是一个全局变量的地址,这就不需要修正,相应的relocatable文件里就是0。

不得不说这是一个很聪明的hack!

还有,如果你看最后executable文件,你可能又困惑了,call后面的修正似乎和上面不一样。举个例子:

80483ba:       e8 18 00 00 00          call   80483d7 <foo>

0x80483ba+0x18明显不是0x80483d7。嘿嘿,这里就不一样了,因为这里需要修正的是-0x5。差的那个会是啥呢?猜猜吧?(用鼠标拖住最后一行看答案。;-)

就是那个e8啊!

关于Linux的syslog

内核中printk发出的消息是这样传递到用户空间的。

内核留给用户空间的接口是syslog(2),glibc对它进行了包装,于是就有了klogctl(3)和syslog(3)。

先由klogd通过klogctl(3)搜集内核消息(见sysklogd/klogd.c),并通过自己实现的syslog()(注意:和syslog(2),syslog(3)都不一样)传递给 syslogd。syslogd根据/etc/syslog.conf的配置情况进行记录。syslogd提供的是一个统一的方式,它不单单记录内核的消息,还包括其它服务器进程的消息,比如Apache,vsftp。

klogd和syslogd用的syslog()的实现用的是Unix domain socket,如果你看源代码(sysklogd/syslog.c)的话很容易就知道这一点。所以,所谓的syslog()/openlog()/closelog()等接口无非就是对这个socket操作的一个包装。这也就清楚了klogd和syslogd之间的通信方式。

根据syslogd的源代码(sysklogd/syslogd.c)来看,记录日志也可以是发送到远程的,而那个socket就是用的inet socket了。

多说一句,其实内核给出的oops只是一堆地址,而把地址和相应的符号对应起来也是由klogd完成的。sysklogd/ksym.c里有搜索System.map的过程,搜索的顺序是:
“/boot/System.map”
“/System.map”
“/usr/src/linux/System.map”

这就是最好的证据。一些细心的人或许还会奇怪,我们不是还有/proc/kallsyms么?怎么不用它?我知道的解释是:为了照顾那些没有/proc文件系统的Linux系统。;-)

我们再来看syslog(3),即glibc实现的syslog()。看一下glibc中的源代码,我们就会发现glibc中的syslog和sysklogd自己的实现类似,也是用unix domain socket来实现的。具体可以看:glibc/misc/syslog.c。

这两种实现之所以都能够传递给syslogd,是因为它们的unix domain socket都是用的/dev/log这个文件。

而我们最常用的查看内核消息的命令dmesg(1)和上面两位守候进程没太大关系,它是直接通过glibc的klogctl(3)函数来读取内核消息的。详细见:util-linux-2.13-pre7/sys-utils/dmesg.c。

如果想了解更多关于syslogd的东西,可以参考这篇文章

想了解内核的中对syslog(2)的实现,可以参考内核源代码:kernel/printk.c。

又hack了一个shell脚本

正如董溥同学给我留的言,coolcode插件不支持C语言,这是事实。而且用coolcode插件往wordpress里贴代码也是不很爽~!

于是乎,我就hack了一个脚本,调用vim来生成html,然后往博客里贴时复制里面的html代码就是了。恩,我知道emacs有个htmlize插件,可惜它生成的html是CSS的,貌似wordpress不支持直接贴那玩意(未经验证)。我用它更新了一下前面一篇文章中的代码,效果还不错,代码如下:

#!/bin/bash #Copyright(C) 2008, WANG Cong #GPLv3 applies. if (($# != 1)) ; then

        echo "Bad usage!"

        exit 1

fi if [ ! -f $1 ] ; then

        echo "$1: No such file!"

        exit 2

fi

vim -n -c :so $VIMRUNTIME/syntax/2html.vim -c ":w $1.html" 

        -c ":qa" $1  > /dev/null 2> /dev/null

exit 0

生活的意义在于折腾

有句话说得好:“生,容易。活,容易。生活,不容易!”

生活很多时候都会是很平淡的,时间长了就会觉得无趣。这时候别着急,你得学着折腾,没事折腾点事来做。这样的生活才会精彩! 折腾够了这个,歇歇再折腾那个。让生活不再那么无聊!

有时候,生活也会不那么顺心,别着急,把它当成生活给你提供的“折腾”,这样省得你再自己折腾!折腾过去了再回头看看,生活不还是得继续么?还是得重回无趣?

然后就接着折腾……

生命不息,折腾不止!

聪明的墙

“这些墙很有趣。刚入狱的时候,你痛恨周围的高墙;慢慢地,你习惯了生活在其中;最终你会发现自己不得不依靠它而生存。这就叫体制化。 ”——《肖申克的救赎》
我发现,墙忒有才了!

首先,墙懂得正则表达式!它对”^wiki“域名的网站一概过滤,而”wiki$”却没事。

其次,墙知道今天是愚人节!为了幽大家一默,今天破例可以访问blogspot和en.wikipedia.org!

如果第2条猜测不成立,即明天仍可以访问,那就说明墙懂得支持闹运会。8月24之后应该就会关闭!

如果最后一点仍不成立,那说明你在做梦!

哎,墙啊,你这玩笑开得太突然了!突然没了你俺受不了啊!俺这心挖凉挖凉的!

(今天距离北京闹运会结束还有145天。。。)

Happy Joking!

我发现,一本正经的扯淡也是一种本事。老外们对干这种事乐不知疲啊~!

先是RFC中的扯淡,凡是April 1发布的RFC基本上都是(全都是?)joke性质的。从1989年到2007年,只有2006年没有,其它几年还有一次发布好几个的~! 这里有一个搜集,列出了每年4月1号的RFC,非常有意思。当然了,里面最出名的一个恐怕是IPv9的那个了,更joking的是居然有人把此当正事去做!(不许联想!!否则后果自负!)

当然啦,带有joke性质的RFC不光是这一天有,有几年在其它日期也出现了。更搞笑的是,连大名鼎鼎的Cerf(Dr. Chen 的偶像) 也来joke了一把。有兴趣的同学穿墙去看微机百科好了~!如果你NB到可以提交RFC,看看这个。俺期待着某年的今天看到你写的RFC!

今天lkml上也joke了一把,一本正经地说kernel.org要停机,原因是要从Fedora Core 5升级到FreeBSD!真逗~~!俺也回复了一把,说根据RFC 1606,Linux kernel应该考虑汇入net/ipv9这个分支吧~! ;-)

Update:谷歌今天也不甘寂寞,joke了一把

Happy Joking!