Liuw’s Thinkpad

想要赢就先学会输,想要成功就先学会失败

思考

with 2 comments

每个人都会有低谷,每个人都会有不如意的时候,正视自己。

无论是优点也好,缺点也好,对自己的了解是必须的。

Written by liuw

2009/05/20 at 09:47

Posted in 生活

Tagged with

流量控制的一个小问题记录

leave a comment »

洗澡时突然回想起自强邮件列表上一个学弟提到的问题,初步问题是如何让不同的程序走不同的网络(Web浏览器和BT),深层次的问题是如何让不同的协议走不同的网络。

我初步提出的解决办法有两个:一是设置本地代理;二是使用iptables的l7-filter。

代理的实现原理是让代理选择出口,这样只要为两个程序开两个本地代理即可。这解决的是“初步问题”。

用l7-filter是为了解决“深层次问题”。我个人没有使用过l7-filter,我的想法是,只要能把流量标记出来,那么就可以处理。然后学弟说他了解到l7-filter主要是用来做流量控制的,没有这个功能。当时也有其他事情,没有多想。

现在回想起来,做还是可以做的,虽然我没有自己做实验,但是我已经想像到整个流程是怎么样的了。也怪我原来说得不够清楚,只提到了l7-filter。其实l7-filter只是完成标记流量的功能,真正的流量整形,还是得靠tc。

好吧,那么现在我们可以把深层次的要求看作一个设置QoS的问题,那么问题就很好办了。

流程有两步:1. iptables及l7-filter为流量设置标记(–set-mark);2. tc设置QoS参数,把不允许被mark数据流流出的接口对应数据流的速率设置为0(这话挺拗口的)。

具体我就不做了。找点参考文档放下面吧。

  • http://blog.edseek.com/~jasonb/articles/traffic_shaping/scenarios.html,这里面有用tc设置速率的例子。
  • http://lartc.org/,Linux高级路由及流量控制。

Written by liuw

2011/01/30 at 00:12

重置Gnome的Panel

leave a comment »

为自己的Ubuntu装了个Global Menu,没有多想就把原来的两个panel都删除了,到想再加global menu的时候傻眼了——所有panel都没有了,也没有办法加上新的panel了。

Google之后找到了一个重置Gnome Panel的办法。


$ gconftool --recursive-unset /apps/panel

有必要的话再把~/.gconf/apps/panel清理一下,然后把gnome-panel进程重启,默认的panel就回来了。

下次不能再这样傻了。

Written by liuw

2011/01/24 at 13:09

Posted in UNIX-like

Tagged with , ,

Blog的功能应该再纯粹点

leave a comment »

翻了一下自己的blog,大部分的话题都是和技术有关的,小部分是以前的无病呻吟等等等等。

而这很大的一部分技术相关的post,又有相当一部分只是纯粹的笔记性质的东西,只是方便自己查找而记下来的一些小东西。近来越发觉得这样的管理方式不妥当,所以决心还是做点改变吧。

第一,建一个Wiki,去管理一些知识性的东西。Wiki这方面是强项,有目共睹。

第二,blog也不是完全和知识相隔离。blog在记知识的同时,重在自己的一些想法、评价。有原创当时是最好。

第三,blog的功能还要再细分。生活琐事、无病呻吟一类的文章,应该另有去处。技术blog管技术、工作,生活blog管生活、扯淡。

这一篇还算带点自己的思考,所以放这里。

(完)

Written by liuw

2011/01/19 at 20:36

Posted in 戏言

太平生意

leave a comment »

在校内上看到@crackcell上传的一张照片,TX的两个人离职去开串串香小吃店,心里也不清楚什么滋味。

这样的事情也不是一件两件了。细想一下,这个方向也是正确的,衣食住行是每个人都必不可少的。一天不上网不用QQ没啥大事,一天不吃不喝那就受不了了。再极端点,打仗了、饥荒了,大家想到的首先当然是实物性的物资,而不是管自己的QQ号会不会被回收,是吧。

其他行业不清楚,搞IT的就是在做太平生意。世道好了,大家可以安心做,不说有暴富的可能,混个饱饭还是可以的。世道不好,IT那还是靠边站吧,人们更关心是否能吃饱穿暧保证安全。以前多少有点抵触传统行业,因为它们不够“高尖精”,但是现在想到这种想法真是觉得幼稚之极,哈哈。

(完)

Written by liuw

2011/01/14 at 10:38

Posted in 戏言

特权高就是好

leave a comment »

Virtual Machine Introspection就是说只看不改。要是改一下数据会怎么样?

今天就干了这事,在Xen的层面把程序的代码内容给改掉了。简单点说,这就是一种代码注入。

有趣的地方是,改了的机器码最后反映到程序映像之中了。想了一下,大概是因为代码段是以文件映射的方式映射到内存之中的,程序退出的时候会让磁盘上的文件和内存中的内容同步。

往好的方面想,这样的功能是目前最强的hot patch方式。一方面可以on the fly地改进程,另一方面顺带把映像也改了。

往不好的方面想,这样的功能就太可怕了,自己的程序被改了也不知道,重新启动也不成。

不过我原来没有料到会有映像的同步。我一向的理解是这样的只读映射最后只需要把内容丢弃就可以了,代码以后有机会再看吧。

Written by liuw

2010/12/30 at 16:11

Posted in Tech

Tagged with ,

Linux内核中的per_cpu变量实现

leave a comment »

在init/main.c里面有一个setup_per_cpu_areas,会在start_kernel中调用。

这个函数的主要作用就是使用alloc_bootmem为每个CPU在内存中分配一段专属的内存,然后把使用DEFINE_PER_CPU得到的对象模板(存放在.data.percpu一节)拷贝n次(n为配置CPU的个数),再把每个CPU专属区段相对于__per_cpu_start的offset放在__per_cpu_offset数组中(该数组的下标是CPU的ID)。

每个CPU可以通过__per_cpu_start和__per_cpu_offset找到自己的专属区段。

其实挺简单的。

(完)

Written by liuw

2010/12/27 at 11:28

Posted in UNIX-like

Tagged with ,

用一个月时间给自己一个交代

with one comment

刚才把最后一个功能点测试完成,commit了。看了一下log,第一个commit是11月26日,最后这个commit是12月25日,一个月的时间。

对Xen的修改:
12 files changed, 1082 insertions(+), 24 deletions(-)

对Linux内核的修改:
5 files changed, 30 insertions(+), 5 deletions(-)

这一个月,把一个想法从无到有地实现出来,过中的难度只有自己知道。一直认为自己做事有头无尾,把这件事做完了,也算是给自己一个交代了。

内核级别的开发,不容易,但是也说不上很难——这是完成这件事之后最大的感受。与此同时,也对自己、对之后的计划有了一些新的认识和想法。

下面又要开始新的计划了。

(完)

Written by liuw

2010/12/25 at 16:52

Posted in 生活

[好文传递]The TTY demystified

leave a comment »

http://www.linusakesson.net/programming/tty/index.php

Written by liuw

2010/12/21 at 10:14

Posted in UNIX-like, 分享

Tagged with ,

GCC嵌入式ASM快速指南

leave a comment »

本文从Inline assembly for x86 in Linux中摘译。

1 简要GNU汇编语法

1.1 寄存器命名

寄存器名字前面应该加上%前缀。比如要使用eax,那么应该写为%eax。

1.2 来源和目的的顺序

在任何一条指令中,总是先写来源,然后再写目的。这与Intel汇编语法正好相反。

movl %eax, %ebx -- transfers the contents of eax to ebx

1.3 操作数的尺寸

根据操作数的长度是字节、字或者长整形,指令一般需要加上b、w或者l后缀。这不是强制要求的,GCC会根据操作数的尺寸自动加上合适后缀。但是手工加上后缀一方面加强了可读性,另一方面消除了GCC猜错的可能。

movb %al, %bl
movw %ax, %bx
movl %eax, %ebx

1.4 直接操作数

直接操作数需要加上$前缀。

movl $0xffff, %eax

1.5 直接内存引用

使用()去完成直接内存引用。

movb (%esi), %al -- will transfer the byte in the memory pointed by esi to al

2 内联汇编

GCC提供了一种特殊结构去创建联汇编,格式如下:

asm ( assembler template
    : output operands
    : input operands
    : list of clobbered registers
    );

模板由汇编指令构成。input operands是用来作为汇编指令输入操作数的C表达式。output operands依此类推。

asm ("movl %%cr4, %0\n" :"=r"(cr3val))

a    %eax
b    %ebx
c    %ecx
d    %edx
S    %esi
D    %edi

2.1 内存操作数约束

当操作数位于内存中时,所有操作都会直接在内存位置执行。内存操作数约束的作用是当一个C变量需要被内联汇编操作时,程序员不需要显式地把它放到寄存器中。如:

asm ("sidt %0\n" : :"m"(loc));

2.2 匹配约束

在某些情况下,一个变量可能会同时输入和输出操作数。这样的情况可以使用匹配约束来完成。

asm ("incl %0" :"=a"(var):"0"(var));

在我们的匹配约束例子中,%eax同时作为输入和输出操作数。var先被读入到%eax,操作完成后结果被存回var。“0”指定了和0号输出变量同样约束。即是说,它指定了var的输出应该只被放到%eax。这类约束可以在如下的情况使用:

  • 输入是一个变量然后输入到同一个变量;
  • 不需要分别使用不同的变量去保存输入和输出。

使用匹配约束可以有效地使用寄存器。

2.3 常见内联汇编用例

下面的例子展示常见的用法。

2.3.1 “asm”和寄存器约束“r”

int main(void)
{
        int x = 10, y;

        asm ("movl %1, %%eax;"
             "movl %%eax, %0;"
             :"=r"(y) /* y is output operand */
             :"r"(x)  /* x is input operand */
             :"%eax");/* eax is clobbered register */
        return 0;
}

生成的汇编代码如下:

main:
        pushl %ebp
        movl %esp, %ebp
        subl $8, %esp
        movl $10, -4(%ebp)
        movl -4(%ebp), %edx /* x=10 is stored in %edx */
,#APP
        movl %edx, %eax /* x is moved to eax */
        movl %eax, %edx /* y is allocated in edx and updated */
,#NO_APP
        movl %edx, -8(%ebp) /* value of y in the stack is updated with the value in edx */

“r”指明GCC可以采用任意的寄存器。在上例中,edx被先后用于存放x和y。

由于eax在clobbered list中,GCC不会使用它去存放数据。

在上例中,edx被先后用于输入和输出,这里有一个前提就是输入数据总是在输出之前就已经失效了。但是实际情况中有很多指令并不总是这样做的,所以我们可以加上“&”修饰符让输入输出使用不同的寄存器。

int main(void)
{
        int x = 10, y;

        asm ("movl %1, %%eax;"
             "movl %%eax, %0;"
             :"=r"(y) /* y is output operand, note the "&" modifier */
             :"r"(x)  /* x is input operand */
             :"%eax");/* eax is clobbered register */
        return 0;
}

生成下面代码:

main:
        pushl %ebp
        movl %esp, %ebp
        subl $8, %esp
        movl $10, -4(%ebp)
        movl -4(%ebp), %ecx /* x=10 is stored in %ecx */
,#APP
        movl %ecx, %eax
        movl %eax, %edx /* output is in %edx */
,#NO_APP
        movl %edx, -8(%ebp)

2.3.2 指定寄存器约束

下面例子中,cpuid的输入由eax指定,输出到eax、ebx、ecx、edx四个寄存器中。

asm ("cpuid"
     :"=a"(_eax),
      "=b"(_ebx),
      "=c"(_ecx),
      "=d"(_edx)
     :"a"(op));

然后生成如下的代码(这里假设eax等变量存放栈上):

        movl -20(%ebp),%eax     /* store 'op' in %eax -- input */
,#APP
        cpuid
,#NO_APP
        movl %eax,-4(%ebp)      /* store %eax in _eax -- output */
        movl %ebx,-8(%ebp)      /* store other registers in
        movl %ecx,-12(%ebp)        respective output variables */
        movl %edx,-16(%ebp)

strcpy可以用下面的方法实现:

asm ("cld\n rep\n movsb"
     : /* no input */
     :"S"(src), "D"(dst), "c"(count));

2.3.3 匹配约束

拿系统调用的代码做例子:

,#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
{ \
long __res; \
__asm__ volatile ("int $0x80" \
        : "=a" (__res) \
        : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
          "d" ((long)(arg3)),"S" ((long)(arg4))); \
__syscall_return(type,__res); \
}

通过使用匹配约束“0”,系统调用号被放入到eax中。

2.3.4 内存操作数约束

考虑如下的原子减一操作:

__asm__ __volatile__(
        "lock; decl %0"
        :"=m"(counter)
        :"m"(counter));

会生成如下的汇编:

,#APP
        lock
        decl -24(%ebp)
,#NO_APP

上面的例子中,变量在内存中直接被减一。假如使用“r”的话,操作就没有原子性了。

2.3.5 clobbered约束

考虑如下的memcpy实现:

asm ("movl $count, %%ecx;
      up: lodsl;
      stosl;
      loop up;"
     :
     :"S"(src), "D"(dst)
     :"%ecx", "%eax");

lodsl和stosl隐式地使用eax,ecx被显式地加载到寄存器中。除非我们用clobbered约束告诉GCC这两个寄存器是可用的,它不会再使用它们去存放其他数据。esi和edi没有加入到clobbered列表中,因为它们已经出现在了输入操作数列表中。准则就是,例如一个寄存器在asm中使用了(无论是显式还是隐式),而又没有出现在输入、输出操作数列表中,那么它就必须出现在clobbered列表中。

Author: Wei LIU
<liuw at liuw dot name>

HTML generated by org-mode 6.21b in emacs 23

Written by liuw

2010/12/20 at 10:59

Posted in 分享

Tagged with , , ,

LD_PRELOAD的trick

leave a comment »

ld.so(8)在为程序加载动态库时,会根据很多不同的环境变量而有不同的表现。这里关注一个LD_PRELOAD的环境变量,此环境变量指定的动态库可以优先于所有其他的动态库加载。

优先加载的动态库中的symbol会override后加载的symbol,所以LD_PRELOAD有一个比较好用的trick就是把一些程序中用的函数替换成自己的版本。

例如,要把malloc和free替换成为自己的实现,可以用:

$ LD_PRELOAD="path/to/my/malloc.so" program

据目前得到的资料来看,一些memory leak检测库、以及一些改进libc函数的库就是这样做的。

但是这个trick也有一定的安全隐患,一些关键函数被恶意、隐式地替换的话,可以想像后果有多严重,所以正常情况下是不推荐使用的。虽然对于setgid/setuid程序有一定的安全防范措施(For setuid/setgid ELF binaries, only libraries in the standard search directories that are also setgid will be loaded),但是一般程序是不会检查的。

Author:
<liuw AT liuw DOT name>

Date: 2010-12-18 23:10:43

HTML generated by org-mode 6.33x in emacs 23

Written by liuw

2010/12/18 at 23:04

Posted in UNIX-like

Tagged with , ,