2010年9月14日

gcc hello world

实例代码:
/*
*  hello.c - Canonical "Hello, World!" program
*/
#include <stdio.h>
int main(void)
{
  printf("Hello,Linux programming world!\n");
  return 0;
}
在命令行上键入以下命令编译和运行这段程序:
$gcc hello.c -o hello
$./hello
Hello, Linux programming world!
第一行命令告诉gcc对源代码hello.c进行编译和链接,并使用-o参数指定创建名为hello的可见程序.第二行命令执行hello这个程序,第三行是程序的执行结果.

其实,gcc首先运行预处理程序cpp来展开hello.c中的宏并在其中插入#include文件所包含的内容:然后把预处理后的源代码编译成为目标代码;最后,链接程序ld创建一个名为hello的二进制文件.

现在我们来通过手工操作重新创建这些步骤,以逐步执行编译过程.第一布是运行预处理器.使用-E选项告诉gcc在预处理后停止编译过程:
$gcc -E hello.c -o hello.cpp
此时查看hello.cpp会发现stdio.h的内容确实都插到文件里去了,而其他应当被预处理的标记也做了类似处理.
下一步是将hello.cpp编译为目标代码.可使用gcc的-c选项来完成:
$gcc -x cpp-output -c hello.cpp -o hello.o
-x选项告诉gcc从指定的步骤开始编译,在本例中也就是编译器处理后的源代码(cpp-output).
gcc是怎么知道如何处理某种特殊类型的文件呢?它是依靠文件的扩展名来决定如何正确处理该文件的.
——————————————————————————————
扩展名                       类型
.c                            C语言源代码
.C,.cc                       C++语言源代码
.i                            预处理后的C源代码
.ii                         预处理后的C++源代码
.S,.s                       汇编语言源代码
.o                            编译后的目标代码
.a,.so                       编译后的库代码
———————————————————————————————
最后,链接目标文件,生成二进制代码.
$gcc hello.c -o hello

--
we drink green tea

ssh登陆时如何触发执行shell脚本

在你的用户目录下面,打开或者创建.bashrc文件,在里面添加一行"echo "hi"",保存退出,然后ssh到这个账户看看echo有没有被执行

--
we drink green tea

GCC汇编器语法

GCC汇编器语法
GCC汇编器语法
   由于Linux内核代码使用GCC汇编器语法,如果可以了解的话,对理解内核有一定帮助。我结合了一些资料总结了一下。由于本人初次研究且水平有限,涉及到的可能只是很简单的一部分,希望各位大虾拍砖。
  
 A. GCC汇编器语法 //////////////////////////////////////////////////////////////
 
  GCC编译器使用AT&T语法。它与Intel语法有几个主要的不同点:
  1. 操作数的目的和源位置颠倒
     在Intel语法中,第一个操作数是目的,而第二个操作数是源;而AT&T则正好相反
  2. 寄存器命名
     在AT&T语法中,寄存器被加上了%前缀,写为%eax等
  3. 立即操作数
     在AT&T语法中,立即操作数往往需要$前缀,对于16进制的数字加上0x前缀,例如$0x4F;
     在Intel语法中往往是4fh,用'h'作为后缀
  4. 操作数大小
     AT&T语法中,操作数占内存大小决定于汇编命令操作符的最后一个字符的内容。 操作符以'b', 'w'和 'l'为后缀指明内存访问长度是byte(8-bit), word(16-bit)还是long(32-bit). 而Intel语法在操作数前加上'byte ptr','word ptr'和'dword ptr'的内存操作数(这个操作数不是汇编命令操作符)来达到相同目的. 
     因此, Intel "mov al, byte ptr foo" 用AT&T语法就是 :"movb foo, %al" 
  5. 内存操作数
     在Intel的语法中,基址寄存器用'['和']'扩起来,但是在AT&T中改用'('和')'。 此外,在Intel语法中一个间接内存寻址: 
     section:[base + index * scale + disp],在AT&T中则为: 
     section:disp(base, index, scale) 
     总是需要记住的一点就是,当一个常数被用作disp或者scale时,就不用加'$'前缀。
  对比的例子:
  Intel Code                    AT&T code
  mov eax,1                     mov $1,%eax
  mov ebx,0ffh                  mov $0xff,%ebx
  int 80h                       int $0x80
  mov ebx,eax                   movl %eax,%ebx
  mov eax,[ecx]                 movl (%ecx),%eax
  mov eax,[ebx+3]               movl 3(%ebx),%eax
  mov eax,[ebx+20h]             movl 0x20(%ebx),%eax
  add eax,[ebx+ecx*2h]          addl (%ebx, %ecx, 0x2),%eax
  lea eax,[ebx+ecx]             leal (%ebx,%ecx),%eax
  sub eax,[ebx+ecx*4h-20h]      subl -0x02(%ebx, %ecx, 0x04),%eax
 
B. 基本形式的内联汇编 //////////////////////////////////////////////////////////
 
以下2种都合法:
__asm__("assembly code");
asm("assembly code")
如果我们有多余一条的指令,可以分行写,每行要加上"",每个指令末尾添加\n\t,这是因为GCC将每行指令作为一个字符串传给as(GAS),使用换行和TAB可以给汇编器传送正确的格式化好的代码行。
C. 扩展形式的内联汇编 //////////////////////////////////////////////////////////
前面介绍的基础形式的内联汇编方法只涉及到嵌入汇编指令。在高级形式中,我们将可以指定操作数,它允许我们指
定输入输出寄存器(内联函数使用这些寄存器作为存储输入输出变量)和程序中涉及到的clobbered寄存器列表(clobbered
registers:内联汇编程序可能要改变其内容的寄存器)也并不是一定要要显式指明使用具体的寄存器,我们也可以把它留给GCC去选择,这样GCC还可能更好的进行优化处理。高级内联汇编的基本格式如下: 
   asm ( assembler template 
        : output operands /* optional */ 
        : input operands /* optional */ 
        : list of clobbered registers /* optional */ 
        ); 
其中assemblertemplate包含汇编指令部分。括号中每个操作数用C表达式常量串描述。不同部分之间用冒号分开。相同部分中的每个小部分用逗号分开。
例如:
    int a=10, b; 
    asm ( "movl %1, %%eax; 
          movl %%eax, %0;" 
         :"=r"(b) /* output */ 
         :"r"(a) /* input */ 
         :"%eax" /* clobbered register */ 
        ); 
上面代码所做的就是用汇编代码把a的值赋给b。值得注意的几点有: 
1) "b"是输出操作数,用%0来访问,”a”是输入操作数,用%1来访问。 
2) "r" 是一个constraint, 关于constraint后面有详细的介绍。这里我们只要记住这里constraint
"r"让GCC自己选择一个寄存器去存储变量a。输出部分的constraint前必须要有个"=",用来说明是一个这是一个输出操作数,并且只写。
3) 你可能看到有的寄存器名字前面写了两个%,这是用来帮助GCC区分操作数和寄存器。操作数只需要一个%前缀。 
4) 在第三个冒号后面的clobbered register,%eax说明在内联汇编代码中将要改变eax中的内容,GCC不要用它存储其他值。 
当这段代码执行结束后,"b"的值将会被改掉,因为它被指定作为输出操作数。换句话说,在"asm"内部对b的改动将影响到asm外面.
 
D. 汇编模板 ////////////////////////////////////////////////////////////////////
 
每条指令放在一个双引号内,或者将所有的指令都放着一个双引号内。每条指令都要包含一个分隔符。合法的分隔符是换行符(\n)或者分号。用换行符的时候通常后面放一个制表符"\t"。我们已经知道为什么使用换行符+制表符了(前面部分有解释)。其中,访问C操作数用%0,%1等等
 
E. 操作数 //////////////////////////////////////////////////////////////////////
 
C语言表达式(大多情况是C变量)将作为"asm"内部使用的操作数。每一个操作数都以双引号开始。对于输出操作数,还要写一个修改标志(=)。constraint和修改标志都放在双引号内。接下来部分就是C表达式了(放在括号内)。 
标准形式如下: 
"constraint" (C expression) [ 如: "=r"(result) ] 
对于输出操作数还有一个修改标志(=)。 constraint主要用来指定操作数的寻址类型(内存寻址或寄存器寻址),也用来指明使用哪个寄存器。如果输出表达式不能直接寻址(比如是bit-field),constraint就必须指定一个寄存器.这种情况下,GCC将使用寄存器作为asm的输出。
现在我们来看一些例子,把一个数字乘以5使用汇编指令lea 
asm( "leal (%1,%1,4), %0" 
    : "=r" (five_times_x) 
    : "r" (x) 
   ); 
这里输入操作数是'x',不指定具体使用那个寄存器,GCC会自己选择输入输出的寄存器来操作。如果我们也可以让GCC把输入和输出寄存器限定同一个。只需要使用读写操作数,使用合适的constraint,看下具体方法: 
asm( "leal (%0,%0,4), %0" 
    : "=r" (five_times_x) 
    : "0" (x) 
   ); 
上面使输入和输出操作数存在相同的寄存器中,我们不知道GCC具体使那个寄存器,但是我们也可以指定一个,像这样: 
asm( "leal (%0,%0,4), %0" 
    : "=c" (five_times_x) 
    : "c" (x) 
   );
 
F. Clobber List ////////////////////////////////////////////////////////////////
 
一些指令破坏了一个寄存器值,我们就不得不在asm里面第三个冒号后的Clobber List中标示出来,通知GCC这个里面的值要被改掉。这样GCC将不再假设之前存入这些寄存器中的值是合法的了。我们不需要把输入输出寄存器在这个部分标出,因为GCC知道asm将使用这些寄存器。(因为它们已经显式的被作为输入输出标出)。如果此外指令中还用到其他寄存器无论显示还是隐式的使用到(没有在输入输出中标示出的),这些指令必须在clobbered list中标明。
如果指令中以不可预见形式修改了内存值,要加上"memory"到clobbered list中。这使得GCC不去缓存在这些内存值。还有,如果内存被改变而没有被列在输入和出部分 要加上volatile关键字。 
如果汇编代码必须在我们放的位置被执行(例如不能被循环优化而移出循环),那就在asm之后()之前,放一个valatile关键字。 这样可以禁止这些代码被移动或删除。
 
G. 常用constraints /////////////////////////////////////////////////////////////

   o. 寄存器操作数constraint(r)
   constraints "r"被指定时,GCC可能在任何一个可用的通用寄存器中保存这个值。当然如果你要指定具体使用那个寄存器就要指定具体使用哪个寄存器的
   +---+--------------------+
   | r |    Register(s)     |
   +---+--------------------+
   | a |   %eax, %ax, %al   |
   | b |   %ebx, %bx, %bl   |
   | c |   %ecx, %cx, %cl   |
   | d |   %edx, %dx, %dl   |
   | S |   %esi, %si        |
   | D |   %edi, %di        |
   +---+--------------------+
   
   o. 内存操作数constraint(m)
   当操作数在内存中时,任何对其操作将直接通过内存地址进行。和寄存器constraint相反,内存操作是先把值存在一个寄存器中,修改后再将值回写到这个内存地址。寄存器constraint通常只用在对速度要求非常严格的场合。因为内存constraint可以更有效率的将一个C语言变量在asm中跟新[不需要寄存器中转],而且可能你也不想用一个寄存器来暂存这个变量的值。
 
   o. 匹配constraint 
   某些情况下,一个变量可能用来保存输入和输出两种用途。这种情况下我们就用匹配constraint 
   asm ("incl %0" : "=a"(var) : "0"(var)); 
   这个例子中eax寄存器被用来保存输入也用来保存输出变量。输入变量被读入eax中,incl执行之后eax被跟新并
   且又保存到变量var中。这儿的constraint "0"指定使用和第一个输出相同的寄存器。就是说,输入的变量应该只能放在eax中。这个constraint可以在下面的情况下被使用: 
   a) 输入值从一个变量读入,这个变量将被修改并且修改过的值要写回同一个变量; 
   b) 没有必要把输入和输出操作数分开。
   o. 其他constranints
   a) "m": 使用一个内存操作数,内存地址可以是机器支持的范围内
   b) "o": 使用一个内存操作数,但是要求内存地址范围在在同一段内 。例如,加上一个小的偏移量来形成一个可用的地址
   c) "V": 内存操作数,但是不在同一个段内。换句话说,就是使用"m"的所有的情况除了"o"
   d) "i": 使用一个立即整数操作数(值固定);也包含仅在编译时才能确定其值的符号常量
   e) "n": 一个确定值的立即数。很多系统不支持汇编时常数操作数小于一个字。这时候使用n就比使用i好
   f) "g": 除了通用寄存器以外的任何寄存器,内存和立即整数
   
   在使用constraint的时候,为了更精确的控制约束,GCC提供了一些修改标记,常用的修改标记有: 
   a) "="指这个输出操作数是只写的;之前保存在其中的值将废弃而被输出值所代替。 
   b) "&"用于对输出操作数的修饰。当使用它进行修饰时,等于向GCC声明:"GCC不得为任何输入操作数分配与此输出操作数相同的寄存器"。其原因是&修饰符意味着被其修饰的输出操作数要在所有的输入操作数被输入前输出。

--
we drink green tea

2010年9月12日

上厕所用英语怎么说

汉语"去方便一下"是一句婉转语,即"去洗手间"。如今在一些正式场合,很少有人会说"去厕所"。在过去,"厕所"本来也是婉辞,原意是"侧面的房子"。("茅房"过去也是婉辞,因为居住的正房多用瓦盖,而厕所则比较简陋,通常用茅草盖。)

  英语里表示"厕所"的婉辞更多。在多年前的英语课堂上,我们认识了washroom和WC(water closet的缩略语,原指"盥洗室")。这两个词如今在美国已很少被使用,现在美国人一般说restroom或bathroom,英国人则多说lavatory(在美语中,只有火车或飞机上的厕所才被叫做lavatory)。此外,英国人常用toilet指厕所或马桶,而美国人则只用其指马桶。

  一些文化人还给"如厕"起了许多有趣的名称,比如:comfort station, cloakroom, retiring room, public convenience, house of amusement, chamber of commerce, old soldiers' home。

  在英国,人们有时将"厕所"称为loo,据说由于英国许多门牌号为100号的房屋多为厕所,loo与数字100形似,故而得名。

  在一些非正式场合,表示"想去方便一下"的说法则更多:

  男士:I'd like / I want / I am going..。

  to go somewhere, to go into retreat, to go to the bank, to go to the john, to go to my private office, to go to Egypt, to go to tap a kidney, to cash a check, to pluck a rose, to shake hands with an old friend, to ease oneself, to shoot a lion, to release one's nature, to water the lawn, to shake dew off the lily。

  女士:I'd like / I want / I am going..。

  to fix one's face, to powder one's nose, to freshen up, to get some fresh air, to go and see one's aunt。

  在聚会时,英美朋友如需要去方便一下,他们有时并不明说,而是说May I be excused?或May I adjourn? 这时,你千万不要问他/她要去哪里。当然,小朋友们通常会直截了当地说:I wanna pee pee/piss/make water/go to the pot. 如果你在外国朋友家做客,想去方便又不知道厕所在哪,不妨婉转地问主人:What is the geography/layout of the house?


--
we drink green tea

how to install g77 in ubuntu

I just added the following lines to the source.list after the lines of universe repositories for intrepid:

Code:
deb http://hu.archive.ubuntu.com/ubuntu/ hardy universe 
deb-src http://hu.archive.ubuntu.com/ubuntu/ hardy universe
deb http://hu.archive.ubuntu.com/ubuntu/ hardy-updates universe
deb-src http://hu.archive.ubuntu.com/ubuntu/ hardy-updates universe
(Note: hu should be changed to your country code i.e. us, gb, de, etc.)

after that in the terminal:

Code:
sudo aptitude update
sudo aptitude install g77
That worked for me.

--
we drink green tea