2010/9

长途旅行物品检查列表

每次出远门之前我都纠结于该带哪些东西,想想东西不多,可一收拾起来还真不少,真后悔我那个45L的背包当初买小了。可我每次又都是不慌不忙,直到出发的前一天晚上才开始收拾,所以每次都有点儿手忙脚乱。

这次回来我就想整理一个详细的检查列表,把能想到的东西都想好,这样每次出门之前对着这个列表检查就可以了。

下面是我自己整理的一些,想到再补充:

1. 手机,备用手机电池,手机充电器。除非你去的地方没手机信号,那就带GPS吧。

2. 相机,备用相机电池,相机电池充电器,备用相机存储卡。我这个卡片机的一个好处是它用的是普通的五号电池,所以充电电池要是没电了去商店买南孚电池也可以。如果万一存储卡都不够的话,准备几张空DVD吧,到时找个地方把照片刻出来。

3. 雨衣,雨裤,雨伞。通常用不到,但是一旦下雨就必须有了。这几种看情况而选,比如你去爬山或者骑车的话,你肯定用不到雨伞;如果只是腐败游的话,雨伞足够了。

4. 太阳镜,防晒霜。去海边的话最好都带上;去高原的话最好带上防晒霜,去爬雪山的话也需要,尤其是太阳镜。可是我从来没买过防晒霜,所以这次去青海西藏时鼻子上被晒得脱皮了。

5. 拖鞋,毛巾,洗漱用品(主要是刷牙和洗头洗澡用的)。视出门的天数而定,出门时间长的话最好都带上,住的青旅很可能没有这些东西,或者住的地方很简陋(青海湖边住宿就是最好的例子)也不可能有。有一双自己的拖鞋穿还是很舒服的,尤其是夏天。

6. 衣物。视季节、气候和地方而定。去高原的话昼夜温差比较大,出发之前建议看一下当地的天气预报,气温大概是多少,该准备的衣服都备好。衣服比较多的话,有一个种节省空间的方法,就是把衣服都一件一件卷起来,真的能省不少空间!速干衣服最好备着,尽管你可能也带着雨衣。内衣、袜子要多准备一些。冲锋衣最好带上,既能保暖挡风,又能当雨衣用。

7. 纸巾(干湿两种)。干纸巾不用多说,很常用。对于我来说带着它还以备流鼻血,因为我吃辣的吃多了就流鼻血。湿纸巾可以在没地方洗脸的时候用,我不是开玩笑,真有这种情况。自行斟酌。女士最好备好大创可贴,我是一爷们儿,这方面不方便多说。

8. 小手电筒或头灯。走夜路或扎营必备。爬比较高的大山我都是选择夜爬,拿着手电筒真是不太方便,准备买一个头灯。除非你很确定不走夜路,那带着吧。

9. 腰包。之前我也没有,这次出门多亏带着它。骑车时带上还是很方便的,这样裤子口袋里就不用塞手机之类的东西。腰包了除了放钱包和手机之外也可以放一些纸巾,放一包烟和打火机,放一些证件之类的。分离这些东西的还一个好处是你住在某个地方之后,可以把除了它之外的包放在房间里,出门吃饭只要带着它就够了。

10. 药品。因个人身体情况而定。一般要带上治感冒发烧的,治上火的,治拉肚子的,如果去高原还要带治高反的,都是以防万一,用不到当然更好!如果夏天住宿条件差的话,最好带上风油精,即能驱蚊又能提神。

11. 食物和水。能不带就不带,能去当地买就别现在买,一是因为带着太占地方、占重量,二是可能你吃不完然后浪费了。如果真要带的话,估算好一共需要带几顿饭,都是哪一顿。如果体力消耗很大的话最好也带上几罐红牛

12. 刀子。不用多说,吃饭时切肉什么的很方便。最好带一把瑞士军刀,然后开啤酒的起子也有了。不过坐飞机时一定要注意啊,千万要把刀子放到托运的包里,否则你就扔给机场吧。

13. 登山杖、护膝。要爬山就都带上,尤其是下山时,带护膝能明显保护你的膝盖。如果徒步的话,最好带一对登山杖。

14. 扎营装备。如果扎营的话那一套都得带着,帐篷、防潮垫、睡袋、地席、营灯。所以你还得有个大包才行啊!

15. 几本书。如果路上坐车时间比较多的话,带上几本书可以打发时间,最好找些适合旅途上看的,比如短篇散文。也可以带上一本笔记本,记一下路上每一天的感受。

16. 塑料袋。一种用来装垃圾,一种用来放穿过的内裤、袜子,一种用来防潮。

17. 手套。冬天出门的话一般会用到。骑车的话一定要带啊,否则骑时间长了手会很疼的。

18. 百变魔巾。这个是最有意思的东西,出汗的时候能当头巾用,骑车的时候能当口罩,围脖用,不戴的时候还能当毛巾来擦汗。

附几条户外经验:

1. 冬天最好带着保温杯,能在山顶上或路上累了喝一口热水很舒服的!

2. 关于路上吃饭。早饭一定要吃热的,一定吃饱!尤其是你当天要消耗大量体力的话,一上午的体力全靠你这一顿早饭支持着,所以必须重视早饭。午饭没必要吃太饱,如果时间紧张要吃快。晚饭要吃饱,也要吃热的,要是扎营的话带着炉头升火做饭吧。

3. 补充能量的东西:巧克力、牛肉干、奶片。我的感觉是,巧克力是最给力的!吃一块德芙巧克力能骑出好几公里……我还没吃过那种叫能量棒的东西。

4. 半路上不要喝酒,尤其是白酒,否则你腿会发软。晚上住宿时可以喝。

5. 压缩饼干能不吃就不吃,因为它很难吃,但是如果真吃的话它也确实很撑时候。

6. 如果去的地方不方便取钱,带着现金,走之前估算好要带多少。如果带的比较多的话,分开放,多的部分放到大包里,少的部分带在身上。

Gcc Trampoline

gcc对trampoline的定义如下:

A trampoline is a small piece of code that is created at run time when the address of a nested function is taken. It normally resides on the stack, in the stack frame of the containing function.

trampoline是因nested function应运而生的。其基本原理描述如下:

The instructions in the trampoline must do two things: load a constant address into the static chain register, and jump to the real address of the nested function. On CISC machines such as the m68k, this requires two instructions, a move immediate and a jump. Then the two addresses exist in the trampoline as word-long immediate operands. On RISC machines, it is often necessary to load each address into a register in two parts. Then pieces of each address form separate immediate operands.

下面我们来看看它具体是怎么工作的。看这个例子
[c]

include

int function(int arg) {

    int nested_function(int nested_arg) {
            return arg + nested_arg;
    }

    return nested_function(arg);

}

int main(void)
{
printf(“%dn”, function(10));
}
[/c]
很明显我们使用到了一个nested function,但是我们看gcc生成的汇编:
[asm]
00000000004004c4 :
4004c4: 55 push %rbp
4004c5: 48 89 e5 mov %rsp,%rbp
4004c8: 89 7d fc mov %edi,-0x4(%rbp)
4004cb: 4c 89 d0 mov %r10,%rax
4004ce: 8b 00 mov (%rax),%eax
4004d0: 03 45 fc add -0x4(%rbp),%eax
4004d3: c9 leaveq
4004d4: c3 retq

00000000004004d5 :
4004d5: 55 push %rbp
4004d6: 48 89 e5 mov %rsp,%rbp
4004d9: 48 83 ec 10 sub $0x10,%rsp
4004dd: 89 f8 mov %edi,%eax
4004df: 89 45 f0 mov %eax,-0x10(%rbp)
4004e2: 8b 45 f0 mov -0x10(%rbp),%eax
4004e5: 48 8d 55 f0 lea -0x10(%rbp),%rdx
4004e9: 49 89 d2 mov %rdx,%r10
4004ec: 89 c7 mov %eax,%edi
4004ee: e8 d1 ff ff ff callq 4004c4
4004f3: c9 leaveq
4004f4: c3 retq
[/asm]

很明显这和普通的函数调用没什么区别嘛!(当然,除了汇编中的nest_function()的名字改变了。)没trampoline什么事。这是因为这时候还没必要使用trampoline,gcc优化还是很聪明的,它不到万不得已不会做一点儿额外的工作。

下面我们就取一下它的地址:
[c]

include

int function(int arg) {

    int nested_function(int nested_arg) {
            return arg + nested_arg;
    }

    return nested_function(arg);

}

int function2(int arg) {

    int nested_function(int nested_arg) {
            return arg + nested_arg;
    }

    int (*function_pointer)(int arg) = nested_function;

    return function_pointer(arg);

}

int main(void)
{
printf(“%dn”, function(10));
printf(“%dn”, function2(10));
return 0;
}
[/c]
这时trampoline就产生了,因为我们对它取了地址,这个地址在栈上,而且nested function()的栈必须被设为外面function2()的栈。
[asm]
00000000004004f5 :
4004f5: 55 push %rbp
4004f6: 48 89 e5 mov %rsp,%rbp
4004f9: 89 7d fc mov %edi,-0x4(%rbp)
4004fc: 4c 89 d0 mov %r10,%rax
4004ff: 8b 00 mov (%rax),%eax
400501: 03 45 fc add -0x4(%rbp),%eax
400504: c9 leaveq
400505: c3 retq

0000000000400506 :
400506: 55 push %rbp
400507: 48 89 e5 mov %rsp,%rbp
40050a: 48 83 ec 30 sub $0x30,%rsp
40050e: 89 f8 mov %edi,%eax
400510: 89 45 d0 mov %eax,-0x30(%rbp)
400513: 48 8d 45 d0 lea -0x30(%rbp),%rax
400517: 48 83 c0 04 add $0x4,%rax
40051b: 48 8d 55 d0 lea -0x30(%rbp),%rdx
40051f: b9 f5 04 40 00 mov $0x4004f5,%ecx
400524: 66 c7 00 41 bb movw $0xbb41,(%rax)
400529: 89 48 02 mov %ecx,0x2(%rax)
40052c: 66 c7 40 06 49 ba movw $0xba49,0x6(%rax)
400532: 48 89 50 08 mov %rdx,0x8(%rax)
400536: c7 40 10 49 ff e3 90 movl $0x90e3ff49,0x10(%rax)
40053d: 48 8d 45 d0 lea -0x30(%rbp),%rax
400541: 48 83 c0 04 add $0x4,%rax
400545: 48 89 45 f8 mov %rax,-0x8(%rbp)
400549: 8b 45 d0 mov -0x30(%rbp),%eax
40054c: 48 8b 55 f8 mov -0x8(%rbp),%rdx
400550: 89 c7 mov %eax,%edi
400552: ff d2 callq *%rdx
400554: c9 leaveq
400555: c3 retq
[/asm]
读生成的汇编,我们可以看出堆栈大体这样:


[ xxx ] <-rsp
[ eax ]
[ 0xbb41 ]
[ addr ]
[ 0xba49 ]
[ rsp ]
[0x90e3ff49]

[ xxx ] <- rbp

其中addr是指nested_function.2079的地址。这里最让我们困惑的应该那三个常数,它们是什么?根据上面的定义你应该可以猜出,是指令!到底是什么指令呢?我们手工反汇编一下:
[c]
unsigned short arrary[] = {0xbb41, 0xffff, 0xffff};
unsigned short array2[] = {0xba49, 0xffff, 0xffff};
unsigned short arrary3 [] = {0xff49, 0x90e3};
[/c]
其中0xffff仅仅是用作标记。把此文件保存为decode.c,然后:


cr0% gcc -c decode.c
cr0% objdump -D decode.o

我们可以得到,它们大体就是下面三条指令:


movl $nested_function.2079,%r11
movl %rsp, %r10
jmp *%r11
nop

根据nested_function.2079里的代码,我们可以看出%r10传递的是参数的地址,然后就直接jmp到nested_function.2079里去了。这就是传说中的trampoline!

注:此时的stack必须是可执行的,因为有代码放在了里面,查看其maps可以看出:

bfebe000-bfed3000 rwxp 00000000 00:00 0 [stack]

提到nested function,不能不提一个trick,就是用nested function来实现C的lambda!如下:
[c]

define lambda(l_ret_type, l_arguments, l_body)

({                                                           
  l_ret_type l_anonymous_functions_name l_arguments          
    l_body                                                   
  &amp;l_anonymous_functions_name;                               
})

qsort (array, sizeof (array) / sizeof (array[0]), sizeof (array[0]),
       lambda (int, (const void *a, const void *b),
               {
                 dump ();
                 printf ("Comparison %d: %d and %dn",
                         ++ comparison,
                         *(const int *) a, *(const int *) b);
                 return *(const int *) a - *(const int *) b;
               }));

[/c]
怎么样?很有意思吧。

痛苦即人生

以前对凡高了解很少,只知道他是一个割耳、开枪自杀的怪才。读了这本《凡高画传》才知道,原来他一生都是生活在痛苦之中!

他一生默默无闻,穷困潦倒,基本上一直在靠他弟弟提奥的经济支持活着。开枪自杀时年仅三十七岁。

作为一个画家,他一生仅卖出去一幅画——《红葡萄园》,而非他死后被拍出天价的《向日葵》。他一生仅办过一次个人画展,还是在他弟弟提奥的家里。无论怎么看都不能称得上成功。

作为一个普通人,他与这个社会似乎格格不入,还经常被人们驱赶,送进精神病院。他与别人能和谐相处的时候并不多,都是喜欢让他作画的农民,更多的人则是厌恶他,把他当作一个疯子来看。

作为一个男人,他终身未婚。他追求过两个姑娘,均遭到无情地拒绝。好不容易遇到一个喜欢他的姑娘,结果姑娘的家人极力反对,最后以这位痴情的姑娘的自尽而告终。

无怪乎他的临终遗言是“痛苦即人生”了!这是对他一生最好的写照。

在他这一生当中唯一对他关心备至的就是他的弟弟提奥,他的画他都细心的保管着,他写给他的信他都仔细珍藏着,直到去世他也是死在了这位弟弟的怀里。可见,人生得一知己足以!

所以,年轻人,你还有什么看不开的啊?你那点儿痛苦和凡高这痛苦的一生比起来又算得了什么!

加上萨特那句名言,正好凑成一对:他人即地狱。痛苦即人生。这或许才是对人生最好的概括……

Jump Label

从gcc 4.5开始,gcc 内嵌汇编开始支持一个叫jump label的东西。说白了,其实就是在gcc 内嵌汇编中支持外面C语言的goto label。不能访问外面C语言的goto label一直以来都是gcc内嵌汇编的一大缺陷。来自Red Hat 的 Richard Henderson向gcc社区提交了这个想法

最初的动机是因为内核要tracer需要这个东西,因为现在的tracer都是静态实现的,类似于:

[c]
if (unlikely(tracer_is_enabled))
trace();
[/c]

这样显然增加了一个额外的 if 开销,每次都要判断是否需要调用trace()。

而如果jump label 实现的话,那么我们就可以用汇编把需要调用trace()的那部分代码放到一个goto label之下,把这个goto label存放到一个单独的 section 里。而当启用或禁用某个tracer时,我们就可以修改里面的代码!换句话说,如果tracer没有启用,它里面放的就是nop指令,而如果tracer开启,那么我们就把一个jmp指令复制到那个位置,让它跳转到那个label从而去调用trace()!

下面就是用jump label来实现的这个功能的最重要的部分:
[c]

define JUMP_LABEL_INITIAL_NOP “.byte 0xe9 nt .long 0nt”

define JUMP_LABEL(key, label)

   do {                                                    
           asm goto("1:"                                   
                   JUMP_LABEL_INITIAL_NOP                  
                    ".pushsection __jump_table,  "a" nt"
                    _ASM_PTR "1b, %l[" #label "], %c0 nt" 
                    ".popsection nt"                      
                    : :  "i" (key) :  : label);            
    } while (0)

[/c]

所谓.pushsection和.popsection就是把当前的section也保存起来,然后建立一个新的section,名字就是在后面指定。可见,所有的label都是放在了__jump_table这个section里,格式固定如下:

[instruction address] [jump target] [tracepoint key]

先前代码的地址也是要保存的,因为jmp需要一个offset。更详细的介绍可以参考Jump Label的内核文档

要完全理解它的原理,你还需要读一下整个patch set,尤其是arch_jump_label_transform()的实现。代码不难理解,而且读起来很有意思。

莫道前路无知己

多数时候,我都是自己一个人出门旅行,即使出发之前在网上约一下伴结果也大都不了了之。经常被人放鸽子,习惯了。

其实一个人出去挺不错,除了拍照、拼车可能不方便一些,其它好处也是显而易见的,我自己走我可以随时改变计划和路线,我可以随意选择我想去和不想去的地方,我可以只管照顾好我自己而不用再去照顾别人,我在旅途上有更多的机会认识更多的朋友。

这次出门也一样,走之前很早就准备,本来有一个说好一起去的结果走之前就被放鸽子了,所以还是一个人出发。根据走之前的计划是要去墨脱,一路上只有到了成都才会见到一个朋友,就是那个去年去丽江时认识的妹子。结果因为前面提到的原因墨脱没去,直奔成都重庆了,有幸在那里又认识了好几个新朋友。

环青海湖骑行的时候,前两天我愣是没碰到一个骑自行车的人!直到第三天早上在鸟岛那边才碰到一个反方向骑来的哥们,他告诉我和我同方向的前面有一哥们,后面还真遇到了这个哥们,张凯。他是从西宁骑过来的,准备去格尔木,从那里骑车到拉萨。所以那天我们基本上都在同行,因为我们骑得快,所以当天下午5点就已经超前到了哈尔盖(刚察前方二十多公里),晚上一起吃饭喝酒聊天。第四天他坐火车去格尔木,我坐车回西海镇。后面几天我基本上一直在赶路,等到了成都才给他发短信,他已经顺利到达拉萨了!我们约好等回到北京一起喝酒。

在拉萨的时候,因为同住“天文之家”,所以碰见了豆瓣上的“小囧貓斯拉”。看名字还以为是个姑娘,见面才知道是一个纯爷们儿。他在拉萨待了好几个月了,所以周边都逛完了。我在的那天本来是要跟他们去哲蚌寺的,结果等我从布达拉宫回来他们已经出发了。只在拉萨待了一天两个晚上,然后就从川藏线出来了。

在川藏线路上认识了一个吉林的哥们,呃,礼貌地讲应该是大叔,也是很喜欢玩户外的。虽然年纪比我大多了,但是玩得比我还厉害,十分佩服,不知道等我到了那个年纪还会不会像年轻时这样?一路上我们都在交流爬山徒步的经验。他邀请我到冬天的时候去吉林滑雪。

到了成都住在梦之旅青年旅舍(推荐一下,里面的氛围不错,非常适合驴友),遇到了各种各样的人,其中一个哈尔滨的哥们,田宁,第一天和我住同屋的,聊得很投机。后面几天我因为去峨眉山,去重庆,虽然没继续住在那个房间,但是一直和他见面聊天、打牌。在成都的最后一天终于见到了Moorekang,一个湖南小伙子,在我出发之前就说到了成都要招待我,去峨眉山也多亏了他指点。在川大,他带我们逛了一圈还请我们吃了顿饭。再次谢过!:)

去重庆的时候看望了一个哥们,快一年没见了,结果晚上吃火锅时喝得太多,丢人现眼了,晚上都不知道怎么回去的。第二天见到了Wrinkle同学,对,就是放我鸽子的那个!大帅妞一枚。她带我去逛了洪崖洞,坐了坐过江缆车,然后大热天的我们顶着四十度的高温去了中央公园……

这次最遗憾的是没见到小佳妹子,也是快一年没见了,在成都的时候她一直都很忙,要么在上班要么在加班,各种不给力。说到姑娘,我走过全国很多地方,发现还是重庆和四川的姑娘最给力了!

看!这不一路上都是朋友吗?记得当初出国的时候,小公子给我发了一条短信,“莫道前路无知己,天下谁人不识君。”所以我也经常把这句话送给那些出远门的朋友。放心走吧,“海内存知己,天涯若比邻!”

带上耳机去旅行

在青藏旅行一路上除了绝美的风景之外,还有唱不完的山歌情歌,“没完没了的姑娘, 没完没了地唱”。这些地方没有大城市里的浪漫,但是也少了大城市的拜金、浮躁,所以到这里你或许能遇到更纯真更真挚的爱情。

出发之前给自己准备一首《我要去西藏》,品味一下那种“幸福安详”。

青海湖骑行的第一站就是西海镇,快进西海镇的时候,你可以在路边看到王洛宾的那句“在那遥远的地方”。只有来到里青海湖这里你才能切身体会到这首歌的意境。青青的湖水,翠绿的草原,连绵不断的山丘,方圆几公里之内经常见不到一个人、一辆车,随处可以见牛羊,使你仿佛置身于王洛宾当年来过的地方。只是我们再也看不到那位牧羊的“好姑娘”了……

从青海出来之后坐上开往拉萨的火车,一路翻山越岭,此时应该配一首《坐上火车去拉萨》,我们“坐上了火车去拉萨,去看那神奇的布达拉”!

到了拉萨可以去看看布达拉宫,去大昭寺拜拜佛,去逛一下八廓街,或者干脆在拉萨的街上随便走走。拉萨的街道很干净,而且高楼很少,所以远处的高山几乎随处可见。路上可以看到很多手里拿着转经筒赶去朝拜的人,偶尔你还会见到在马上磕长头的人。到了晚上,不妨到拉萨的酒吧坐坐,或许你能体会到拉萨特有的一种静谧。

从拉萨走川藏线出来,路上经过一个地方,叫康定。快到康定的时候,你可以在不远处的山上看见“康定情歌”这四个大字。就算你不知道康定,但你一定听过这首《康定情歌》。可想而知,康定当年也是一个浪漫的青年男女相遇相爱的地方。

川藏线虽然条件很艰苦,但是你仍然可以看到不少骑车去拉萨的强人。从成都到拉萨,川藏线南线全长2200多千米,骑行大约需要24到28天。骑行川藏线需要的不仅仅是体力,更重要的是坚强的意志。我觉得能骑完川藏线国内你就没有什么路不能骑了!在此向每一个骑行川藏线的人致敬,你们都是“威武雄壮的汉子”!

西藏归来

我已经于19号早上顺利抵达北京,一路虽然劳累,但是非常开心。感谢留言的qwe同学关心!

在拉萨的时候遇到一个从墨脱返回来的哥们,他告诉我去墨脱的一座桥被冲毁了,有20多人被堵在了背崩,等桥修通。他是直接从背崩反穿回拉萨的!其实那种桥修通也快,说不定一两天就行,但我的行程安排的太紧张,实在没法等了。所以我就决定直接从川藏线走了,直接到成都了,路上用了5天时间。

今年气候反常,雨水特别多,林芝地区那些天一直都在下雨,翻越多雄拉雪山时经过的瀑布都可以没过腰!去是很危险的。听他们说5号那天有一位向导不幸牺牲在了去墨脱的路上,当然另一个主要的原因是他年纪比较大了。在那个哥们的相机了还看到一个震撼的照片,一个人受伤了,四个人抬着他翻山出来!所以,去墨脱一定要谨慎啊,千万不要赶在雨季!血的教训啊!

游记和照片会很快补上。刚回来,很多很多邮件需要处理,公司也有一些事需要做,所以比较忙,对不住了。

明天中秋节,祝大家中秋快乐!