2015年3月8日星期日

网易云课堂Linux内核课程作业1:一个简单汇编代码的分析

关于:豆丁老豆  原创作品转载请注明出处 《Linux内核分析》MOOC课程 http://mooc.study.163.com/course/USTC-1000029000
题目要求在Linux下反汇编下面一段c代码:
int g(int x) 
{
    return x + 7; 
} 
int f(int x) 
{ 
    return g(x); 
} 
int main(void) 
{ 
    return f(11) + 3; 
}

通过实验楼这个网站,可以使用虚拟的linux环境,截图如下:


反汇编编译代码,执行命令:

gcc -S -o main.s main.c -m32

得到包含汇编代码的main.s文件,如下(忽略了开头以“.”开始的无关信息,第1列是行号):

1 g: 2 pushl %ebp 3 movl %esp, %ebp 4 movl 8(%ebp), %eax ------------(8) 5 addl $7, %eax ---------------(9) 6 popl %ebp 7 ret -----------------------------(10) 8 f: 9 pushl %ebp 10 movl %esp, %ebp 11 subl $4, %esp 12 movl 8(%ebp), %eax -------------(5) 13 movl %eax, (%esp) --------------(6) 14 call g -----------------------(7) 15 leave ---------------------------(11) 16 ret ---------------------------(12) 17 main: 18 pushl %ebp 19 movl %esp, %ebp ---- (1) 20 subl $4, %esp ------- (2) 21 movl $11, (%esp) -----(3) 22 call f --------------(4) 23 addl $3, %eax --------(13) 24 leave 25 ret --------------------(14)

为了了解计算机是如何工作的,我们可以模拟cpu、内存、寄存器等是如何解释执行的这段汇编代码的:

(1) 从main开始,pushl、movl的2行语句是进入一个新函数时对函数调用堆栈进行的例行操作。这里详细解释下:
(1.1) pushl负责占用新内存用来保存原始ebp,执行时又分为subl和movl 2个子操作步骤:subl指令中esp寄存器所指向的栈顶增长(占用新的内存空间),movl指令中保存调用main时在ebp寄存器中保存的调用者堆栈底地址(如果是在Shell中执行main程序,这个堆栈可能属于调用main的shell程序用的)。
(1.2) molv负责初始化ebp,将ebp修改为保存在esp寄存器中的栈顶内存地址,作为main函数的堆栈的底部,此时main函数的堆栈是空的,所以栈顶和栈底都是一个相同的地址。



(2)subl代码将esp中的地址减4个字节(共32 bits),由于堆栈在内存中是向下增长的(内存地址越小,堆栈中的位置越高),所以减小地址,就意味着栈顶增长,增加堆栈的长度,在这里增加了32个bits,看来是准备存放一个long int的数据大小了(long是32位,我们是翻译为32位计算机的汇编代码,因此内存地址都是32位的,图中的“内存地址”实际上应该乘以32,并且降序排列才对,这里简化下,默认+1代表加4个字节,升序标记)。



(3)movl代码将“立即数”11作为一个32位整数放到了 esp 寄存器所指向的内存地址里。对应C代码“return f(11)+3”中,将f函数的参数11保存起来。




(4)call语句调用f函数,因为一个call语句实际上可以分解为push和move语句,其中push如上所述包含2个子指令,负责将eip寄存器中的地址保存到函数调用堆栈中(eip值自动指向下一行第23行,本文用eip(23)代表),栈顶继续增长,然后move指令修改eip寄存器为f的地址(用行号9代表)。由于计算机CPU总是从eip寄存器中获取下一条指令的地址(这就是冯•诺依曼的存储程序计算机结构的伟大之处),因此修改eip后,下面CPU将开始执行保存在f函数里的汇编指令了,CPU从准备执行第23行改为执行第9行。



(5)这一步给eax赋值,一直到mov语句之前的代码刚都解释过了,原理和(1)是一样一样的,保存函数调用入口,栈底指向f函数的堆栈底,栈顶升高,在堆栈中准备好保存一个数值,这个数值在下面第(6)步中进行保存。现在看mov语句的赋值,这里mov语句使用“变址寻址”的方式,将ebp值加8(往堆栈的底部方向数8个字节)赋给eax寄存器,eax就定位到了刚才在第(3)步保存的参数11。至于为什么是8个字节,只要知道如果只数4个字节,就是刚才第(4)步中call代码保存的函数入口地址了,再往堆栈底部数4个字节才是那个long int类型的数值11。另外,这里用到了eax寄存器(累加寄存器)来暂存数值11的地址,这行mov代码用伪C代码可以表示为:

eax = *(int32_t *)(ebp + 8)

int32_t的指针类型数值所指向的内存地址的内容,c的指针表示,简单吧!反正听课的时候我是晕晕的 #:-p 就差点儿浆糊了。




(6)这里就是把eax中的值(数字11的内存地址)放到esp栈顶寄存器所指向的内存空间中。这样我们的f函数的堆栈里面就有“11”这个数字可以供函数内部随时使用了。

(7)调用g函数(类似前述修改eip寄存器来实现)




(8)mov和之前的代码都解释过了,保存函数调用入口,找到之前在f函数的堆栈里保存的参数“11”,并暂时放在eax寄存器里。


(9)add语句将11加7,eax = 18




(10)pop语句前面push语句保存函数调用入口的逆过程,这是cpu准备从g函数回到f函数的节奏了。pop语句会将esp寄存器所指向栈顶的值出栈,具体这条代码是将其存放到了ebp寄存器中,同时栈顶降低(加4个字节),堆栈长度缩短。


ret语句继续进行出栈操作,把之前第(7)步call语句在esp中保存的eip地址拿出来赋给eip寄存器,CPU就回到第(7)步call语句的下一句去执行了。

(11)leave语句是回到上一个函数的堆栈中,可分解为mov和pop语句,即先将当前执行函数f的栈底move放到栈顶寄存器中,然后再出栈pop,pop的原理在第(10)步已说明,这里将esp栈顶中保存的上一个函数的栈底地址放回到ebp寄存器中,这样ebp就指向了上一个函数(调用f的g函数)的堆栈栈底,然后栈顶降低,,至此,我们就离开了f函数的堆栈,它可以被OS回收了。堆栈寄存器esp、ebp们都恢复到了调用f前的g函数堆栈使用情况。

f函数使用“leave”和g函数使用“pop ebp”返回上一个调用函数的区别,leave相对多了一个把ebp的值mov到esp里的操作(即修改栈顶,指向栈底),因为g函数没有对栈顶进行修改,所以离开g的时候不需要leave,直接pop出f函数的栈底就好,而f函数对栈顶做了修改(保存参数等操作),所以要用leave先恢复栈顶指向栈底,然后才pop出main函数的栈底。

(12)同第(10),让cpu跳转到main函数。


(13)把eax加3,eax = 18 + 3 = 21


(14)同第(11)和(12),用leave和ret这一组动作就是作废main函数的堆栈,cpu跳转返回到调用main函数的程序去。其中OS会把eax中的值21,作为main函数默认返回值返回。因此如果你在shell里执行main后,再执行 echo $?,shell应该是输出21。

总结:从上面的分析可以看到,cpu是代码的执行者,代码都放在一段内存中(CS段),用eip寄存器去自动指向下一条待执行的指令,这些指令包括mov、add、sub等基本操作和pop、push、leave、ret、call等复合操作,它们对堆栈和寄存器的值进行存取和加减运算,这些操作可以实现c等相对汇编的高级语言中的语义,比如函数调用、加减运算、返回调用者等,堆栈随着函数调用而增长,随着函数使用到的参数而增长,函数完成计算后,中间结果保存到类似eax这样的寄存器中,然后出栈操作使堆栈又缩短还原,直到最后的main函数也执行完毕,堆栈归零。









2012年12月16日星期日

《韵学骊珠》密码

《韵学骊珠》终于看懂怎么用了,方法其实也简单,从头开始读几个例字就能推断了。先记下几个标点符号的意思,备忘也方便其他新手菜鸟使用。
1. 书按韵部分多个章节(每韵注明收音);
2. 每韵分“平、上、去、入”和“阴、阳”等声调分别罗列;
3. 每个声调又分“宫、商、角、徵、羽”5种发音音阻部位,同心圆符号分隔;
4. 每音阻类又按4呼(出音:“开、齐、撮、合”或“鸡鸭鱼肉”的口型)和清浊音分类,大圆圈符号分隔;
5. 每个字(大号字体)下面有小号字体写的解释和切音、本音(指入声字的北曲同音字)、其它读音等(如:“又音xy”,表示其他读音同字x和y),没有的话表示这个字的切音同上一个字。

上面不清楚的看《曲韵易通》即可。还有几个标点符号搞清楚,每个字下面的小圈是分隔符,竖线是代替本字的符号。

练习:查“數”字的4种读音和释义。(目录后面有繁体笔画检字表)
..
..
..
..
(参考答案见下)

本音 shu(包括阴上的动词和阴去的名词,姑模韵),又音 chuk(阴入声,屋读韵,形容词细密也)shuok(阴入声,约略韵,形容词多次)

2011年11月27日星期日

bitcoin thoughts - the value

On bitcoin.org, value of bitcoin is claimed to depended on the requirement of bitcoin user, the more demand the higher the value, not based on the computer power required to produce (mine) bitcoins -- a myth that proposed by Labor Value Theory (LVT).

Since Marxism concluded that only labor can produce new value, and this is a critical point of marxist political economics. I am going to make my own judgement by recovering the related financial knowledges.

Asume marxism theory is correct, then the value of bitcoin is defined by the social necessary labor time needed to "mine" bitcoins, this includes the constant capital: electricity, cost of computers, bitcoin mining softwares and Internet access; and the variable capital: mining workers's labor time.

Considering the bitcoins can be produced almost at no cost if the algorithm is not a hard computing problem and without the total bitcoin number limit, the social necessary labor time of bitcoin almost equals zero. This means bitcoin are almost the same value as paper based currency, which itself has no value, but is only accepted by some goverment to exchange any thing equals the face value. The we have the following propositions:

currency value = face value = can be exchanged with any commodity the goverment has with the same value

bitcoin value = face value = can be exchanged with any commodity the bitcoin community has with the same value

So, instead of increasing bitcoins by the bitcoin network, to maintain a steady value of bitcoins, it should backed by real value possessed by bitcoin community-- such as programming hours, hosting service, ebay items etc. It's like virtual money, but the amount is a predictable computer program result, and the exchange rate with US dollar can be determined by:
1. value possessed by bitcoin community and amount of bitcoins, which determin the real "use value" of bitcoin
2. exchange value of US dollar ( such as 50 dollar = 1 programming hour of one hacker )
3. demand and supply between US dollar and bitcoin
4. There is no 4. :)

Let's try to validate above statements by reviewing:
1. With other conditions keep unchanged, if bitcoin amount is kept up with the total real value which can be provided by the community, then the value represented by bitcoin is steady. This requires the bitcoin network ( the "Sky Net" of bitcoin ) only produce new bitcoins when it needs to buy real new value from the community ( not the old value-- old value already exchanged by bitcoins). Like the Fed bank buy US government's bonds with new USD, and the government pay USD to anyone selling commodity to it. ( The amount of USD needed by the market is always less than the total value of commodity in the market, as USD is M1 of currency, the M1 formular can be found in any textbook of finance ). In practice, it may happens like that: Hacker A has coded a unix tool for 2 hrs, suppose the market value for this 2 hrs is 100 bitcoins, then customer B loan 100 bitcoins from bank C, bank C mines 100 bitcoins with no cost, but only a 100 bitcoin credit record in B's bank statement, then B buys this tool and accurally pay A 100 bitcoins. That is, the more people loan from bitcoin bank to buy new commodities, the more new bitcoins should be mined from nowhere. In bitcoin community, anyone can be a bitcoin bank, only if other users in this community trust them -- I will only trust someone who has enough wealth and very good bank operating reputation.
2. With other conditions keep unchanged, if only US dollar inflats, then one bitcoin can buy more US dollars, the bitcoin exchange rate will go high against USD.
3. With other conditions keep unchanged, if only more people need bitcoins instead of USD, then exchange value of bitcoin ( price of bitcoin in USD) goes up.

Next, I'll wait for anyone who can provide value statements with a Demand based Value Theory. Or continue provide more practical and accurate formulas of bitcoin exchange rate.




2011年8月14日星期日

ASUS TF101 EeePad root and reflash to TW firmware

The week before last week, I bought an Android Pad, the Asus TF101 CN version in Guangzhou, I need to reflash it with some oversea firmware to use google services.
After reading XDA and some other sources, I finally flashed a TW version follow these steps (US/WW version should be the same procedure):

[edit: just run the universal script to root you TF101, following text before section *Change SKU* is obsoleted, and, you don't need change SKU to have TF101 rooted]

0. Before you begin, get a Ubuntu Linux Distro as working environment, because many tool support this platform and it do not need install drivers.
0.1 Familiar with the procedure with posts 1 and 2 from XDA forum.

1. First, we need the root privilege to overwrite system boot image from a TW firmware by using android adb command tool. But the Nvidia Tegra firmware is encrypted, so we need a special nvidia dev tool to flash the BIOS (on the Nvidia Tegra ROM) with a new cracked boot.img file, Download NVFlash tool for linux, it's riped from NVIDIA Linux Dev Tool by some hacker and including the Secure Boot key of Asus TF101. If you have flashed the BIOS already, skip to rooting procedure below.

[# procedure of cracking BIOS]

1.1 Boot into XDA mode and make a backup of current firmware:
#!/bin/bash

export PATH=$PATH:.

# all code copied from http://forum.xda-developers.com/showthread.php?t=1142567

BACKUP_DIR=~/tf101-backup-`date +%Y%m%d%H%M%S`

mkdir $BACKUP_DIR

nvflash --bct transformer.bct --setbct --configfile flash.cfg --bl bootloader.bin --odmdata 0x300d8011 --sbk 0x1682CCD8 0x8A1A43EA 0xA532EEB6 0xECFE1D98 --sync

nvflash --resume --getpartitiontable $BACKUP_DIR/partitiontable.txt

nvflash --resume --read 2 $BACKUP_DIR/02_BCT_raw.img

nvflash --resume --read 3 $BACKUP_DIR/03_PT_raw.img

nvflash --resume --read 4 $BACKUP_DIR/04_EBT_raw.img #bootloader

nvflash --resume --read 5 $BACKUP_DIR/05_SOS_raw.img #recovery

nvflash --resume --read 6 $BACKUP_DIR/06_LNX_raw.img #kernel

nvflash --resume --read 7 $BACKUP_DIR/07_BAK_raw.img

nvflash --resume --read 8 $BACKUP_DIR/08_GP1_raw.img

nvflash --resume --read 9 $BACKUP_DIR/09_APP_raw.img #system

nvflash --resume --read 10 $BACKUP_DIR/10_CAC_raw.img

nvflash --resume --read 11 $BACKUP_DIR/11_MSC_raw.img

nvflash --resume --read 12 $BACKUP_DIR/12_USP_raw.img

nvflash --resume --read 13 $BACKUP_DIR/13_PER_raw.img

nvflash --resume --read 14 $BACKUP_DIR/14_YTU_raw.img

#nvflash --resume --read 15 $BACKUP_DIR/15_UDA_raw.img #media (/!\ ~14/30GB large)

nvflash --resume --read 16 $BACKUP_DIR/16_GPT_raw.img
[#rooting procedure is omited, it's as simple as replace a number in a system file, just read the universal script mentioned above]

1.2 Now we can flash the rooted boot.img:
nvflash -r --download 6 boot.img
 
[#Change SKU] 
2. After reboot, we will have a rooted system, and we can update it with any stock firmware from ASUS of any regional SKU. The command is:

升级过程:
1.解压ROM包中的blob文件到adb目录中
2.将TF101与电脑连接
3. 进入到adb文件目录中
4.输入命令 adb push blob /data/local/
5.稍等几分钟后会提示blob文件就被传送到机身存储中
6.继续输入命令 adb shell
7.此时提示符变为#
8.输入命令 dd if=/data/local/blob of=/dev/block/mmcblk0p4
9.设备会自动重启,开机即为所刷ROM.


At last, I reflashed the rooted boot image with nvflash tool to install some system apps which require a rooted device.


2010年8月1日星期日

Dell mini10v (1011) 多系统启动 w/ hackintosh成功

A little different from Allan Kelly's recipe:
1. I preserved the Dell preinstalled hardware diagnosis tools hidden partition.
2. I installed Win 7 ultimate 32bit edition
3. bootloader is using EasyBCD installed on Win 7 ( It's very powerful, and easy to use, I tried this after Chameleon failed to boot itself at the last stage, and Win 7 BCD bootloader is shown up instead )
4. I installed Ubuntu netbook remix 104 LTS instead of standard desktop version.
5. I installed Grub2 with Ubuntu to my /dev/sda, and it's working good.
6. Last but not the least, I installed OS X 10.6.3 with NetBookInstaller 0.8.4 RC1. I avoided upgrade to 10.6.4.
7. I followed this post on MyDellMini forum to fix sleep/awake problem.

more on easyBCD, it can boot Linux, Mac OS X, with my configuration, it's actually boot Grub2 for Linux, and Chameleon for Snow Leopard resp.

My partition layout:
1. Dell HW Diag Tool hidden partition (primary, FAT, 39M)
4. OS X (primary, HFS+, 58G)
2. reinstalled WinXP SP3 (primary, NTFS, 18.78G)
3. extended partition
5. Win 7 (logical, NTFS, 29G)
6. Ubuntu Netbook Remix 104 (logical, ext4, 12G)
7. Ubuntu swap partition (logical, 2G)
8. free space

One last note: I used Asus Super Slim usb HD (size: 30G), instead of usb keydrive which is slow and opt to be worn out very quickly (I bought a 8G Kingston DataTraveller USB keydrive, and have to return it back several times to replace it). And I suggest resize the partitoin on external usb HD to as small as possible to speed the formating/copying process up.

2009年7月7日星期二

recover the Windows XP in bootcamp

Yesterday, I tried to install Ubuntu on an external usb disk for my new macbook (already dual boot with Windows XP and OS X), but I forgot to check how Ubuntu installer would install the Grub, which turns out to make my Windows XP on the internal disk unbootable with a message like this: " GRUB hard disk error".
After some trial and correction, I recovered the XP with following steps:
1. Boot the laptop from XP installation CD
2. When prompted, press R to enter the recovery console
3. fixmbr
4. fixboot

2008年10月15日星期三

用firefox给医改提意见的方法

为了用电邮方式提交你的个人意见给国务院医改小组,而你用的又是firefox,那么为了解决网页上错误的javascript阻止你发表意见,你需要:
1. 安装greasemonkey 插件
2. 访问医改意见反馈网页:http://www.ndrc.gov.cn/yg
3. 添加下列用户脚本:
// ==UserScript==
// @name new
// @namespace my
// @include *
function On_Submit()
{

if(check(document.addForm))
{
window.open('','check_method','width=418,height=200');
document.addForm.submit();
}
}
// ==/UserScript==


第2个脚本:

// ==UserScript==
// @name sum
// @namespace http://2ban
// @include http://www.ndrc.gov.cn/ygyj/vcode.jsp

document.addEventListener('click', function(event) {
// event.target is the element that was clicked

// do whatever you want here
document.forms[0].submit();
// if you want to prevent the default click action
// (such as following a link), use these two commands:



event.stopPropagation();
event.preventDefault();
}, true);

// ==/UserScript==
4. 刷新页面,在出现输入校验码时,用tab键选择输入框输入,不要用鼠标点选,输入完毕后,用鼠标点提交即可。(抱歉我第一次用greasemonkey,javascript也忘了怎么用,所以大家将就用吧)

总之,我希望使用firefox的用户也有参与公共事物、发表个人意见的权力和渠道。

2008年9月11日星期四

为motorola Z6转换视频文件

按照z6手机的说明,该手机支持h263 /3gpp格式的视频,但发现其随机附带的视频用linux下的mplayer播放时检测为mpeg4/aac 编码的文件,这比h263所使用的单声道音频效果自然好很多,参考网上的资料,经检测下列命令适合把网上常见的mpeg4 podcast视频转换为可以在Z6上播放的节目,并获得mp4的视频压缩效果和aac立体声音频效果:
系统要求:
debian或ubuntu,添加对应的non-free源,如multimedia.debian.org (莫名其妙被大陆政府封锁),medibuntu.ubuntu.org
下载带non-free组件支持的ffmpeg程序

操作步骤:
1. 下载mp4文件,比如从miro订阅的podcast频道下载,假设名为 channel.m4v
2.
ffmpeg -i channel.m4v \             #源文件
-acodec libfaac \ #目标文件音频编码
-vcodec mpeg4 \ #目标文件视频编码
-r 10 \ # 每秒10帧的fps,Z6手机支持的最高可能是15
-s qcif \ #使用h263支持的分辨率和屏幕大小 176 x 144,这种分辨率没必要考虑字幕,更本看不清的,所以建议尽量牺牲视频的质量来缩减文件大小。
channel.3gp #目标文件

网上也有分离音视频(demux or rip),然后对视频用多pass来转换,最后在合成(mux),以提高视频效果的实现,但对于我的Z6简直是浪费。
如果你对声音的要求也很低,那么acodec可以用libamr_nb 或libamr_wb,这个对于人的语音是够了,vcodec可以用h263。

2008年6月12日星期四

how to play amr audio files

amr is 3gpp standard audio format, mplayer may support it natively in near future, or you can compile the amr codec into mplayer yourself.

But I'm lazy, so when I found this amr file on internet, I downloaded it and transferred to my motorola phone with bluetooth, so that I could play it.

另外偏题一下,上面这个电话录音是当事人自己公布的,不是我窃听的。里面是中产阶级的夫妻俩在吵架,妻子借批评孩子不好好学习来埋怨丈夫不好好做自己的正事,老给家里惹麻烦,宣泄自己对cops的fear,对未来的恐惧。 情感真实,本色出演,比任何肥皂剧都感人,更有现实意义,背景信息可以看这里:http://groups.google.com/group/cuihua/browse_thread/thread/7f0a4ce23638234f

2008年6月11日星期三

how to choose a condom

Warning: This is not a scientific article, it's from my personal experience.

Condom is an easy and safe way to protect your sex mate, but because most of them are made from some kind of nature rubber, it's has bad heat conductivity, and can reduce the sensibility. So I prefer to use the super thin type (here I mean skinny not smaller ). I found the diameter is not important, and choose a smaller one has no improvement for my sex life. I think, it's because tighter condom is still thick than the thin type of normal or size, unless it's as small as a tooth-stick :)

I haven't try other type besides thin, smaller and normal type. Of course, I hate to use condom, but it's the best choice proved so far.
== RED RIBBON ==
 __
| ))
 X\
/ \\

===== LOVE =====

2008年6月10日星期二

undelete files on vfat filesystem

step 1: Delete your favorite files on a vfat filesystem in a usb-flash drive with command:cd /media/usbkey rm *
step 2: Unmount the filesystem with command: umount /media/usbkey
step 3: Try to remember the path of the deleted files, then undelete them with command: dosfsck -r -u

note: the path begin with slash, from the root of usb drive, not from the mount point.

2008年5月22日星期四

rip audio from mpeg file

time mplayer 惊梦-hxf.mpg -ao pcm:fast -vc null -vo null
you will get a raw wav file, then use lame compress it to mp3.

http://www.doom9.org/index.html?/belight-ac3tomp3.htm

2007年12月18日星期二

《色戒》赏析

google, 新浪上可以看到很多专业精彩影评,肯定很有助于加深理解和回味这部经典作品。看完电影和影评,费点时间记录一些我个人认为非常重要的情节的理解(电影完整版):
1. 王佳芝和自己的同学第二次性交,王佳芝采取的是主动的姿势,身体很兴奋,但脸上毫无享受兴奋之情,有嫖妓经验的同学老实的说“你这次好像有点反应”,王佳芝无不气恼的说“我现在不想和你讨论这个”。

这个情节重要在非常隐蔽的写实,虽然不如影片中另外几次裸戏那么紧张细致,但这是影片写实风格的一个标记,这为王佳芝最后不得不死的结局进行了一个隐喻。就像《红楼梦》于大梦幻处写人物在社会环境中的必然命运一样,黛玉不得不死,不是黛玉多病,而是黛玉可怜。王佳芝就是这么可怜,她是一个花样年华的女大学生,有着对浪漫爱情的向往,对国家民族的诚挚的爱和忠诚,可是看到她在机械的性交的时候,这一次根本没人强迫她,但没人关心她重视她,这和黛玉葬花是完全一样的可怜处境,所谓字字见血,无一字可删,因此,你可以跟着导演大哭一场了。
好的作品就是这样,笔力深厚,于小藏大,于不经意处扼住精魂,如同上乘兵法,春秋巨力,看多了脂砚斋重评石头记和牡丹亭,就能熟悉这种对社会、时代进行反思的艺术技巧,虽说属于技巧,其实就是魅力。

2. 在日本餐馆,汉奸头子也能体会到那时日本人的歌舞如哀嚎,其实他们杀得人越多越恐惧。
这是侵略者和伪政府的内心恐惧,那为什么还要继续杀人呢,因为越恐惧越要杀人!在这里你看到的是无助的历史结局,又一次,点明了王佳芝不能冷酷的执行任务——作为业余级特务的悲惨结局,不论易先生是否可怜爱惜这个娇好性感可爱的女性。痛恨汉奸或者王佳芝的人大可不必在乎王佳芝的死活,但是这个杀人的地狱式循环是所有依赖暴力方式生存的人无法挣脱的紧箍咒。

3. 关于最后毒药一幕,好像很多影评都说王佳芝此时犹豫了,还对生存抱有一线希望或者易先生会特殊关照她,我认为这个大大的误解,是以超然的姿态对王佳芝的侮辱。仔细看那一幕,王佳芝冒着同志和她自己生死攸关压力给汉奸头子告警泄密,那一刻她真的在乎那已饱受摧残的生命么?事败后道路立刻被封锁,在人力三轮车上,她听到人群中一个师奶着急回去烧饭的对话很自然而木然的一笑,很平静的取出毒药-——可是还有必要吞服么,他们这帮sb学生已经没有任何情报价值,等待他们的就是简单例行的询问、行刑、处死,死于自己伪政府的法场上。而她死之前还可以看到她曾有好感的男同学——她一下子回忆起在香港学校剧场里的那一幕——和她的几个同学一起死,至少尸体不孤单。

好片~李安,向你敬礼!

2007年5月21日星期一

牡丹亭上三生路

终于看过了一遍完整的青春版昆剧《牡丹亭》,发文纪念自己祝贺一下。
着迷牡丹亭的“原来姹紫嫣红开遍,似这般都付与断井颓垣”还是因为央视87版红楼梦电视剧第十集“听曲文宝玉悟禅机”结尾的那一段乐曲——就是林妹妹与之共鸣的那首“游园 [皂罗袍]”。详见《脂批石头记》第二十三回“西厢记妙词通戏语 牡丹亭艳曲警芳心”。
当时我根本没注意到也不知道牡丹亭这出明代戏曲,上网搜了歌词才知道的,果然是让人感觉“满口余香”。立刻上土豆网看相关视频,好啊,妙啊。听了好多遍,可就是那“水磨调”的昆曲实在难学出来。
很快,我就弄到了DVD版的青春版牡丹亭来看,称它青春版就是因为主要演员很年轻,里面小生俞玖林的演唱很出彩,网上有人说他真假声转换技巧很高超。他的老师石小梅在新浪有个博客,里面有她唱的《玉簪记》琴挑里的一句(短短一句十来个字,足足唱了2分47秒,呵呵),反正我不懂怎么评赏,只会由衷佩服,叫一个“好!”。
这部DVD实际演出分三天演完,主要演员来自苏州昆剧团,舞美、灯光、剧本、出品等都是台湾的,是我见过的最全的,最多还原汤显祖原戏本的牡丹亭昆剧。而这“全”,就是该部剧最有价值的贡献。说实话,我这几天,听了看了多个版本的牡丹亭,这青春版的表现虽然非常靓丽,但是旦角的唱功和身段——特别是最出名的《游园》一段还是不如我看到的一个江苏昆剧团厅堂版折子戏(就是在传统方形的戏台里表演)水平高、韵味足、动作繁密精巧(虽然我也是不折不扣的门外汉,只能凭感觉欣赏)。
其实,舞台版全本的《牡丹亭》,即使因为演员年轻功力尚未炉火纯青(据说昆剧里旦角都是30来岁才能出师)相对有些稚嫩,却也能让观众如痴如醉,随着剧情变化或哭或笑。可见出品人“忠实”于原著的高明!
作为作品的观众,最讨厌导演编剧自以为是或者迫于外部干预对剧本大肆删改了,如果是因为时间、经费、艺术形式等关系精简当然无可厚非,但是如果把观众当作小孩子,呈现另一个风味的牡丹亭,还说是“全本牡丹亭”的话,那就已经不是汤显祖的“牡丹亭”了。我现在就特别想看到讲述宝玉的好朋友秦钟的央视87红楼梦被删掉那部分!

谢谢出品人白先勇呈献给现代中国人的全本牡丹亭!

呵呵,我现在特别习惯昆剧里的柳梦梅用特别高的声音对这杜丽娘喊” ji~jie~!”(姐姐)。

2007年5月2日星期三

wget离线下载

这里谈的方法比用-m参数稍复杂一点,主要是为了绕过一些服务器用referer这个http header防止离线下载的限制,用此方法请注意不要公开传播下载的文件,应该尊重站长和原作者为大家提供高质量的资源的劳动。

1. 先用wget下载首页,比如index.html,查看源代码,把里面藏有密码的url拷贝下来待用,比如我看到一个首页里藏着“http://59.42.71.245:88/ndatin.aspx?param=ABdXNlcm5hbWU9....",肯定是密钥无疑了。
2. 用wget 加-m参数,再加--referer=URL参数来离线下载资源,URL就是第1步获得的那个地址。

好了,这个方法的确比用cookie限制来的隐蔽。不过看来wget的作者早就碰到这样的问题了。不得不服!

2007年3月24日星期六

看红楼须看脂砚斋评

这两天湖北台在黄金时间重播87版红楼,有几集看得过瘾,有的对话没给出字幕,便去寻原文来对。因记得有人说“脂砚斋”是该书的审校者,因此搜的就是那大名鼎鼎的“脂砚斋评石头记”──《红楼梦》流传最好的版本。
找了对应回目,一路看下来,才发现我们这些现代人要欣赏红楼,一定要结合脂砚斋评语才能尽可能多的领略创作的细节和绝妙处,当然也能看到她认为某些值得作者再推敲的地方。

总之,感觉就像有个博学通古的读伴一样。怪不得有的人就靠写评注出成果的,呵呵,朱熹?

不过,即便是审校者,也并不一定明白知道作者的用意,性别和成长环境差别必然影响对事物的看法,女人总是容易陷得过于细微,何况是个才女。

2007年3月18日星期日

旧日志备份

Sunday Feb 11, 2007

习题6 上下文无关文法

形式语言与自动机,王柏 杨娟,北京邮电大学出版社 第二章习题6
构造上下文无关文法产生L={w|w属于{a,b}* , 且a的个数是b的两倍}








答: S->aXaXb, S->bXaXa, S->aXbXa,
X->aXaXb, X->bXaXa, X->aXbXa, X->e (e表示空串)
思路:S中任意位置可以是a或b或e(开始,中间,结尾),且a的个数是b的两倍——注意S不能为e,故引入非终结符X。

右线性文法习题

形式语言与自动机,王柏 杨娟,北京邮电大学出版社 第二章习题5

找出右线性文法,能构成具有奇数个a和奇数个b的所有a和b组成的字符串。

答:右线性文法的形式是A->wB或A->w, 所以从S开始,第一个字母是a或b:


S->aA, (1)

S->aB, (2)

因为S只能包含奇数个a,所以A中只能有偶数个a,限于右线性文法,需引入非终结字符X:

A->aX, (3)

X->aA, (4)

X->a, (5)

A->e, (e表示空串) (6)

同时A也可以包含奇数个b,因为S有奇数个b,根据(2)构造:

A->S, (7)


同理构造B:
B->bY, (8)

Y->bB, (9)

Y->b, (10)

B->S, (11)

B->e (12)


综合(1)~(12),就是所求文法的生成式P。

能不能再精简呢?



Saturday Dec 23, 2006

最近装的Firefox插件

  • Firefox showcase:一个添加各个tab页缩略图的超有用插件,试想一下,你已经打开了20+个tab,而你又像我一样从来不爱关掉工作用的PC,于是打开 的tab越积越多,要快速找到某个标签页或者整理一下,你一定会抓狂的,直到你安装了showcase...
  • POW 不是战俘,是Plain Old Web server,这是个运行在浏览器里的Web Server,货真价实,而且还能编服务器端脚本(没错,就是javascript)。干嘛用,别人我不知道,我用来做自动配置proxy,只要你喜欢编 程,你会喜欢这个小玩意的,你可以玩AJAX!

POW 0.07有个中文化的bug,导致你打不开option,没关系很容易改,看这儿。

javascript API ref: http://linuxmafia.com/faq/Web/autoproxy.html

Tuesday Dec 19, 2006

wget with cookie

去otn下载软件还要登录,下载又断断续续,不得已请出wget,看看他的功力:

wget -b -t0 -c --cookies=on --load-cookies cookies.txt http://download-west.oracle.com/otn/linux/oracle10g/10201/XXXX.cpio.gz

嘻嘻,搞定!和去sun下载不同的是,sun在url里直接放了sessionid,所以不用那个cookie.txt(我从firefox的目录里拷出来放到另一台wget实际运行的机器里,空间大,又有UPS)。

Monday Dec 18, 2006

我有多怪异"nerdy"?

虽然不知道nerd的确切来源,但说一个有理工科背景的人有多怪异,基本上就可以用nerdy来形容。我有多nerdy,我是不是nerd,我不知道,在一个留美博士研究生的一个weblog里,看到一个测试你有多nerdy地链接,犹豫了一下,对题目忍不住好奇就点进去做了测试,没想到,比那个博士生的分还高,还怪异。

I am nerdier than 72% of all people. Are you nerdier? Click here to find out!



后记:实际上,分数越高越不nerdy.

Friday Dec 08, 2006

用touch解决make的问题

make的时候部分文件修改时间比系统时间晚,导致出现死循环,把所有文件重新touch一下:

find . -depth -print0 | xargs -0 touch -mc

命令串起来就像文字串起来,跟计算机说话的感觉不错 :)

Sunday Nov 26, 2006

tor+privoxy设置

真的很讨厌,ubuntu 610下privoxy的默认设置不会自己加上使用tor,需要手动设置。按照tor的README.privoxy修改/etc/privoxy/config即可。 没有tor查资料还真麻烦,很不爽!



补充一个小技巧,适用于netscape/mozilla/firefox/iceweasel系列浏览器:

  • 为了自动使用proxy来访问某个网站,其它网站使用直接连接,在自动配置proxy的选项中可以指向一个自动配置文件:



这个文件是个javascript脚本,内容如下:

function FindProxyForURL(url, host)
{
if (dnsDomainIs(host, ".wikipedia.org"))
return "PROXY localhost:8118";
else
return "DIRECT";

}
具体语法参看我google到的一个网页。

Monday Nov 06, 2006

Sybase and Tomcat Configuration Notes

测试需要,为Roller配置使用Sybase数据库。这里是我创建的wiki页。 http://rollerweblogger.org/wiki/Wiki.jsp?page=Roller2.3InstallationWithSybase

Tuesday Oct 31, 2006

飘飘飘

2007年3月11日星期日

单侧浆划艇

名词解释
单侧浆:只在艇的一侧划浆。
划艇:不是划船,因为划船特指背对前进方向,呵呵。

与同事争论过能否单侧浆划艇,按照简单的物理知识,这是办不到的──船只会打转转嘛!

可是我亲眼见过一个年轻的渔民这么干过,一个人飞快的划船冲到湖中央把我老爸的鱼钩从渔网上解下来,呵呵,帅呆酷毕了,崇拜到死!电视里也放过一个缅甸还是泰国(抑或老挝?)的少数民族,就生活在湖上,男人们都用一只“脚”非常娴熟的摇浆划独舟,浆靠近舟尾,但还是架在侧边的。

昨天,终于有机会尝试了一把,如果你看到莫愁湖上有个人用一只浆笨拙的划艇,那就是我啦。我摸索的结果(可能不科学,但已经可以比较熟练的驾驭方向和速度,停靠码头等):
1. 动作一:坐船尾最后一排座位,正常划桨,划到末端要靠近船侧。可锻练腹外斜肌或背阔肌。
2. 动作二:转浆面,用力把浆向外拨出水面,这个动作其实就是摇橹。可锻练背阔肌暴发力。

上面两个动作有很多小技巧,都可以锻练到肱二头肌,说起来太麻烦,呵呵,可以免费面授切磋 :-) 物理上分析,两个动作产生的力距在前进方向上的垂直分量可以是相反的。

还有个新体会:和游泳一样,水上运动必须熟悉水性,也就是水上运动的节奏,回想一下,蛙泳的动作即使正确,但如果呼吸和连接的节奏不对,你要么呛水,要么游上几米就没力气了。划艇也是有节奏的,要体会船本身的摇摆,在恰当的时机发力和做动作才能稳定前行,或者及时根据风速、浪、水流来控制方向和速度。

免责申明:注意安全,湖水无情,我不保证上述动作的安全性,不承担由此可能带来的生命财产或任何其它损失的责任。

2007年3月9日星期五

带和不带epsilon转换的NFA的等价

以希腊字母epsilon作为空字符的符号(下面简写为e),带e转换的NFA(不确定有限状态自动机)和不带e的NFA可以通过形式化证明它们的等价性,以下分别记为e-NFA、NFA,他们的转换函数分别记为ed和d。北邮出版的《形式语言与自动机》在这个证明上让我看得不清不楚(一方面是证明步骤不够清楚,但主要是我自己理解的原因),google帮我找到另一个说的很清晰的证明, 只是这个网页是从其它文档转过来的,一些数学符号转换错了,但可以猜出来。

这里想用我自己的理解来说明证明的最后一个步骤:
若 d'(q0,wa)包含q0, 由转换函数的相等性,ed'(q0,wa)也包含q0(条件1),初始状态q0如果被NFA最终状态集F1所包含( q0属于 F1)但q0如果又不属于e-NFA的终止状态集F( q0不属于F)──F与F1不等(F1=F U {q0})。需要证明,F一定有状态被ed'(q0,wa)包含。

此时,由e-NFA转换函数的性质和条件1,q0的epsilon闭包(记为 e*(q0))一定包含于 ed'(q0,wa),因此 e*(q0) 与F的交集A必然在ed'(q0,wa)中。而根据F1定义知,此时集合A非空,即F一定有状态被ed'(q0,wa)包含。此时,结论也成立。

好笑的是,我在南京新华书店看到电子科技大学一位老师写的《形式语言与自动机》里的同一个问题的证明有低级字误,证明里分别讨论“q0不属于F”和“q0不属于F”的“两个”情况,呵呵,而且后面一个步骤的证明居然赫然推导出:其实q0不可能属于F,我的天哪,瞬间晕倒!

google, 我的大学的门。

2007年2月28日星期三

debian的日志循环

我发现一台debian里的某个日志文件总被截断并重新创建,而且每次创建的文件的访问权限不是我所希望的,于是我检查了logrotate的配置,测试ok后到第二天发现,权限设置又不是我所预期的,气得我牙痒痒。重新检查发现:
debian sid下sysklogd自带了管理系统日志文件的循环备份的功能,具体配置文件在/etc/cron.daily/sysklogd。(实际上是使用了debianutils包里的savelog命令)
但大家更加熟悉的是logrotate所提供的日志循环功能。按照UNIX的简单哲学,我更倾向于用logrotate来管理所有的日志文件的循环备份。
用logrotate要注意的是,如果程序在不断的写日志文件,应该用copytruncate参数来保证原始日志文件不动。这时create参数会被忽略。
同时,要避免savelog干预我的日志文件,可修改/etc/cron.daily/sysklogd和/etc/cron.weekly/sysklogd,在用到syslogd-listfiles命令时加 -s 参数来过滤掉特定的日志,比如我的:
for LOG in `syslogd-listfiles -s ha` # Do not handle HA logs. --lanyufeng