哪有什么起因啊,看着在linux kernel中大行其道的汇编代码,自己只能硬着头皮去找点资料来学习,不成想居然找到这么一个强悍的文章,如果你打算自己写一个编译器,那么这篇文章就是为你准备的,在这里
我们借助一个简单的例子,试着揭开linux下的真面目。
int main()
{
printf("hello,world\n");
return 0;
}
在linux下使用 gcc -S test.c 就会产生test.s文件,我在自己机子上可能由于加了头文件,反正汇编后的代码和博客中的代码不太一样。
.file "test.c" .section .rodata .LC0: .string "hello,world!" .text .globl main .type main, @function main: .LFB0: .cfi_startproc pushl %ebp .cfi_def_cfa_offset 8 .cfi_offset 5, -8 movl %esp, %ebp .cfi_def_cfa_register 5 andl $-16, %esp subl $16, %esp movl $.LC0, (%esp) call puts movl $0, %eax leave .cfi_restore 5 .cfi_def_cfa 4, 4 ret .cfi_endproc .LFE0: .size main, .-main .ident "GCC: (Debian 4.7.2-5) 4.7.2" .section .note.GNU-stack,"",@progbits
现在我们只需要关注三个不同的元素:
以__.开头的结构信息,.global main__说明main是一个全局符号可以被其他代码模块引用,.string 暗示一个可以插入到输出代码的字符常量。
以:结尾。它描述了名字和位置的联系。只要调用.LCO立马找到下面的字符串。main:被调用后,立即执行push %ebp(原文是这样表达的,但是我的不一样),在Labels前面用一个.开头的是一个由编译器临时产生的局部变量,其他的就是用户可见和全局变量,现在gcc默认是极大优化的)
如果我们把汇编代码弄成可执行代码,使用以下命令:
gcc -m32 test.s -o test
六个通用寄存器
%eax,%ebx,%ecx,%edx,%esi,%edi
两个堆栈寄存器
%esp,%ebp
bits:
%ah=%al ==> 8 bits. %ax ==>16 bits. %eax ==> 32 bits.
IA-32是 complex instruction set(CISC),so MOV has many different variants that move different types of data between different cells.
Suffix Name Size
B BYTE 8bits
W WORD 16 bits
L LONG 32 bits
在这里分为
global value
immediate value:($56)
register value:(%ebx)
indirect((%sp),也就是MASM中[bx]),
base-relative:(-12(%ecx))(这个语句是说这个值在%ecx暗示的地址(%ecx)下面12字节的内存中).
-12(%esi,%ebx,4): refers to the value at the address -12+%esi+%ebx*4
绝对跳转指令和返回指令需要加"*"
AT&T Intel 说明
Cbtw Cbw 把%al中的字节值符号扩展到%ax中
Cwtl Cwde 把%ax符号扩展到%eax中
Cwtd Cwd 把%ax符号扩展到%dx:%eax中
Cltd Cdq 把%eax符号扩展到%edx:%eaxAT&T
从linus那里pull,当然,前提是你先从linus那里clone一份代码树。
git pull
最好不用 `git pull`,使用`git fetch` 和 `git merge`来代替它.
撤销所有在本地的修改
git checkout -f
查看你所做的修改
git commit -a
撤销最近的提交
git reset HEAD~2
5.List all changes in working dir,in diff format
`git diff`
Dispaly changes since last commit
git diff HEAD
List all changeset descriptions
git log
追踪特定文件的changesets
git log net/ieee80211/ieee80211_module.c
List all branches
git branch
Make desired branch current in working dur
git checkout $branch
Create a new branch, and make it current
git checkout -b my-new-branch master
Examine which branch is current
git status
Obtain a diff between current branch with master branch
git diff master master..HEAD
Obtain a list of changes between current branch with master branch
git log master..HEAD
A one line summary of each changes
git shortlog master..HEAD
假设你在分支A,分支B上完成了工作,你需要把你的工作放进主分支M,
git checkout M
git merge A
git merge B
cd linux-source
git checkout -b tmp v2.6.22
cd linux-kernel-source
git am --utf8 --signoff /path/to/mbox
The –signoff option 暗示git am 在最后加上
Signed-off-by: Your Name <[email protected]>
The name and email are taken from the GIT_COMMITTER_NAME AND GIT_COMMITTER_EMAIL environment variables,(可以设定在.bash_profile 或者相似的文件)
git fetch --tags $URL
Tag a partical commit
cd linux-tree
git tag my-tag
#什麼是愛情
原来ctags的功能这么强大,之前自己是蒙着眼使用的啊。
有人说默认有这个插件,确实有,再下一次吧。
在你的工作目录中,输入以上命令,$是shell的命令提示符,不是命令的一部分,这一点需要注意,这样就会在当前工作目录下产生ctags的标签文件。
xx就是你要查找的变量和函数名
It maybe acted on some impact using “SHIFT + K”
在vim的命令行下输入__:ts__就会列出列表供用户选择满足的变量或者函数(tagslist)。
display preview tags-file and display next tags-file.
jump to the function or variable where whose were defined.
Return where jump from where
Waa…
command:
cscope -Rbqk
-R:表示把所有子目录里的文件也建立索引
-b:仅仅建立符号数据库
-q:生成cscope.in.out和cscope.po.out文件,加快cscope的索引
-k: 在生成索引文件时,不搜索/usr/include目录
vim的normal模式下输入:
:cs add cscope.out
就把索引文件加入到vim中.将以下命令放在.vimrc中,即可省去该命令:
if filereadable("cscope.out")
cs add cscope.out
endif
再试试把下面的内容复制到~/.vimrc里,这样就可以利用相应的快捷键进行不同的查找了. 原文1 原文2 cscope add cscope.out ##4. Commmand & Options After adding the file that is called cscope.out ,we can call cscope find x 简写 cscope f x
c:Find functions calling this function d:Find functions called by this function e:Find this egrep pattern f:Find this file g:Find this definition i:Find files #including this file s:Find this C symbol t:Find assignments to
#taglist 将这三个工具用起来了,然后在命令窗口中键入:
:TlistToggle
在关闭与打开之间转换.
我的vimrc中定义了下面的映射,使用“,tl”键就可以打开/关闭taglist窗口:
map
----------------- |boot sector| | |___________| | | data sector | |_______________|
__________________0x000 |jmp to this code| |________________|0x003 |disk para table | |________________|0x02c/0x03e | part of code | |_______________ |0x1f
一个硬盘在DOS的文件系统下可分为四个基本分区(primairy partition),如果数目达不到所需的数目,可以设置扩展分区(Extended partition ),整个硬盘一张分区表,它存放在硬盘的第一个分区里,而每个扩展分区也都有一张分区表,它存放在扩展分区的第一个分区表中,整个硬盘的主引导扇区(MBR)如下图所示:
------------------ | code | |________________| |partition table | |________________| | setup signal | |________________|
在启动的过程中,BIOS会把Boot Loader读入内存,并把控制权交给它,MBR(硬盘启动)或者启动扇区(软盘)的代码就是Boot Loader的一部分,这部分的实现其实是很复杂的,Boot Loader实际上会寻找各自的启动的扇区。
我的学习过程中有一个很明显的特点,先知道是什么,最后才知道为什么,不知道这样好不好?
http://faq.perl.org/
Programming Perl(Camel book)
Perl 5 Pocket Reference
其实,perl语言是这么一个流程:在内存中保存他的输出;更新内存;并且打印它
1.scalar : a number,a string,You can act on a scalar value with operators(like additioon or concatenation),You can read scalars from file and devices and write to them as well.
2.在整数常量中,如果数字特别巨大,可以使用 21_323_123_987_365表示
3.Others Nondecimal 0377 #377 octal 0xff #FF hex, 0b11111111 #also 255 decimal
4.如果在程序中使用utf-8,这样 use utf8;
5.在字符串的使用中,需要注意’ ‘的内容,里面除了“‘”和“",其余的都代表 他们自己本身,如果想得到一个“\”,那么就使用“\”,为了表示”’“,同样使用“\“转义; 与此对应的是,双引号的使用,你可以想象成c语言中的双引号
6.使用 “.”符号进行链接剪切等操作 For example:
"hello" . "world" #same as "helloworld"
"hello" ' ' . "world" # same as 'hello world'
'hello world' . "\n" #same as "hello world\n"
7.重复字符串”x”,对,你没看错,就是小写字母x,
"yubo" x 3
"yubo" x (3+1)
5 x 4.8 #same as “5555” 最后一个需要说明一下,在操作符 “x”的左边,我们称之为左值,你可以看成源操作数 ,符号右边是右值,你可以看成是目的操作数,4.8被自动转换为4.
8.在数字和字符串之间自由转换,这只是取决于你自己用在标量的的操作符, 比如,“+”系统默认为左值和右值为数字,“.”左右值默认为字符串 , 比如,”12” * “3”就是36,即便在“12yubo34” * 3的结果依旧是36
1.变量
用$表示,$name,…还可以用于数组
2.变量赋值
$bin = 12;
$asd = $bin *2;
另外需要注意的是在perl变量中,“ ”与shell中的“ ”一样, 在比较多的变量中,使用${varible}调用其值
3.打印特殊符号,先找到ascii码,然后使用 chr()函数,$alef = chr(0x05D0); 即可。
4.有关perl的运算符的优先级和结合性(结合性依次降低)
结合性 运算符
left ->
++ --
right **
right \ ! ~ + -(unary operators)
left =~ !~(?)
left */%x
left =-.(binary operations)
left <<>>
< <= > >=
== != <=>
left &
left | ^
left &&
.. ...(?)
right ?:(conditional operator)
right = += -= .=(and similar assignment operators )
left , =>
right not
left and
left or xor
没有必要记住上面的这些东西,如果你找不到你想要的运算顺序,尽管加上括 号即可(parenthses),the same time:
Numeric String
== eq
!= ne
< lt
> gt
<= le
>= ge
##perl中的bool类型 1.如果返回的值是0为false,其他为true;
2.如果返回的是一个字符串,‘ ’意味着false;其他意味着成功
3.如果还有其他情况,请转化为这两种情况。
1.1,Getting User Input
For example:
$line = <STDIN>;
if ($line eq "\n")
{ print "That was just a blank line!\n";}
else { print "The line of input was: $line";}这样就是用户从屏幕标准输入了。
1.2
The chomp Operator
它的作用简单说就是作用于一个变量(输入的值),把结束符(newline)去掉,
这一步在以后的编程中很有用的,上面的例子,我们一般情况下这样做:
chomp($text =
如果你以这样的方式写出这样的程序,那么就没有换行输出了,因为它自动将换行符去掉了。
1.3 in short,chomp也是一个简单的函数,也有返回值,他的返回值就是清除字符的个数,但是这种用法和我们上面不太一样,是这样
$yubo = <STDIN>;
$NAME = chomp $yubo;
输出的结果是1.
1.4 The while control construction 同c语言的一样,很简单的。
1.5使用defined function
$yubo = <STDIN>;
if ( defined($yubo) ) {
print "The input was $yubo\n";}
else { print "No input available\n";}1.
$fred[0] = "yubo"; print $fred[0]; #perl的数组没有限制,随便用
2.列表
(1,2,3) ("yubo",4.5) (1..100)
2.2 The qw Shortcut
qw( fred yubo hechun wilma dino )# 等同于有双引号的列表
qw! yahoo\! google ask msn ! #include yahho! as an element
2.3 List Assignment
3.在给数组赋值的时候,可以在数组前面加上@,这样就全部赋值了。例如,
@rocks = qw/ bedrock slate lava /;
@tiny = ();# the empty list
@giant = 1..1e5; # a list with 100000 elements
The pop operator takes the last element off of an array and returns it @array = 5..9;
$yubo = pop(@array); #$yubo gets 9,@array now has (5,6,7,8)
$barney = pop @array;#barney gets 8,@array now has (5, 6, 7)
push(@array,0) # @array now has (5,6,0)
push @array,8 # @array now has (5,6,0,8)
push @array,1..10; # @array now has those 10 new elements
@yubo = qw# hechun wuhan wangyang #;
$m = shift (@yubo);
$n = shift @yubo;
unshift play an oppose play vs shift,and it used to be filled with elements.
unshift(@yubo, 5);
unshift @yubo, 5;
6.分离数组
1.splice就是分离数组的符号,有4个参数,其中
@yubo = qw(apple, dino, hechun, love);
@removed = splice @yubo, 2; #remove everything after hechun
#@removed is qw(hechun,love)
#@yubo is qw(apple, dino)
2.第三个参数就是要删除元素的个数
@removed = splice @yubo, 1, 2; #@removed is qw(dino, hechun)
#@yubo is qw(apple, love)
3.这第四个参数就是你放置要取代的元素,这个数不必和你取出去的相同。
@removed = splice @yubo, 1, 2, qw(wilma);
当然,你可以不用去掉任何元素,只要使第三个参数变0即可。
7.@和$ 当变量中含有@(list-var)时要注意使用”"转义,还有注意数组的使用。
8.foreach 一个loop的控制变量,一个普遍的用法是用$var读取list的内容,如下:
@yubo = qw(yu hechun hehe);
foreach $num (@yubo){
print "$num\m";
}
注意这时的$num不是简单的@yubo的元素的复制,而是实实在在的东西, 你只要改变$num的内容,也能影响@yubo的内容。我们可以使用$_作为foreach的 默认控制变量,打印语句可以直接使用print;
以反序输出内容,如果是单词,按首字母排序。
如果是单词,按首字母排序;如果是数字,也是按照首位的大小排序。
以上几个内建函数的对象是list(我觉得),使用的时候注意, scalar和list的混用的情况,注意内容与类型的对应要正确。 作者说了,这部分的理解决定了你这一辈子是否使用perl的关键因素, 没有之一。
sub subroutine-name{
}
stores the parameter list in the special array named @_, you can access it to get number of argument and the value of those arguments. For example,$_[0],$_[1]…
在函数内部使用 @_ 就是参数个数
sub max{
if (@_ != 2){
print "wrong\n";
} else {
print "yes\n";
}
}
$n = &max(19,23);
下面的例子,把函数的规则总结的不错
$maxinum = &max(3, 5, 10, 4, 6);
sub max {
my($max_so_far) = shift @_; # private variable
foreach (@_){ #look at the remaining arguments
if ($_ > $max_so_far){
$max_so_far = $_;
}
}
$max_so_far;
}
print "The maxinum is $maxinum\n";
my(var)也叫Lexical(my) Variables,这个变量位于最小的块中,可以是代码块 或者文件。利用关键词my去声明局部变量。
foreach (1..10){
my($square) = $_ * $_;
print "$_ square is $square\n";
}
在代码中你只要使用了这条语句,在使用变量的时候就必须先声明后使用, 不然编译器就报告失败.当然对于内建变量是不会报错的, please use it possiblely. 此时感觉perl真是非同一般,你只要使用了strict,那么程序中的变量就要使用 my去声明。
use strict;
my @name = qw(yubo hechun xixi qianqian);
my $result = &which_element_is("xixi",@name);
sub which_element_is {
my($what, @array) = @_;
foreach (0..$#array){
if ($what eq $array[$_]){
return $_;
}
}
-1;
}
What is state?Please see example follwing:
#!/use/bin/perl
use strict;
sub marine {
my $n += 1;
print "$n\n";
}
foreach (1..5) {
&marine;
}output:五个1。原因在这里很简单,就是my把变量局限于子函数内, 请不疑惑,尽管我们的$n 在sub marine内,但是,在foreach的调用中, 整体已经过去了,所以只会输出五个1(??)
典型例子
while (defined($line = <STDIN>)){
print "I saw $line";
}
同样的表达可以是
while (<STDIN>){
print "I saw $_";
}
foreach (<STDIN>){
print "I saw $_";
}
# Ctrl + D
Reading variables from input,
while (<>) {
chmop;
print "It was $_ that i saw";
}
名字最好使用大写字母,这样有好几个优势。
open CONFIG, 'dino'; # dino is filename
open config, '<dino';
open BEDROCK,'>fred'
you can use a “three-argument” open:
open CONFIG, '<', 'dino';
open BEDROCK, '>', '$file_name';
open CONFIG,'<:encoding(UTF-8)', 'dino';
open LOG, '>>:encoding(UTF-8)', &logfile_name();
if (! open LOG, '>>', 'logfile') {
die "Cannot create logfile: $!"
}
这个判断语句就是判断是否能创建logfile文件,不能的话返回一个数值, 这个值就是不能的含义,在这里,可以把die和pirnt联系起来,共同报错。
Recently i thought sth deeply,English is my shortcut to learn linux kernel and others, and lack of indpendent of thinking.
use strict;
use warnings;
open (my $yubo, '>', 'log');
print $yubo "My first report generated by perl\n";
close $yubo;
print "done\n";
这就是一个典型的文件句柄。open函数可以传入3个参数。
第一个, $yubo,是在 open()调用中定义的标量,第二个参数是读写文件的方式,第三个是文件路径。
文件的内容仍在磁盘上,并不在$yubo变量中,可能你往句柄中写入内容, 东西就会在文件中保存。
这个$yubo就可以类推c语言中的文件描述符(fd),有意思吧!
open(my $yubo, ‘>’, ‘no_exist/file’) or die;
下面这种用法结合前面几种的方法
my $filename = 'No_exist_file';
open(my $yubo, '>', $filename) or die "could not open $filename $!";
# return error information
当时偷懒了,只是简单的记录下来,并不知道什么意思。现在再重新整理整理。 顾名思义,@ARGV就是一个参数,这个参数接受外部变量,这里,这个变量就是某个路径上的文件,将该文件上的内容输出。
@ARGV = ("file1","file2");
while ($line = <>) {
print "$line\n";
}
上面的东西,一看就是菜鸟写的,应该简单一点是这样
@ARGV = ("file1");
while (<>) {
print "$_";
}
For example:
$family_name{'yubo'} = 'flintstone';
$family_name{'hechun'} = 'love';
foreach my $person (qw <yubo hechun>) {
print "I've heard of $person $family_name{$person}.\n";
}
my %new_hash = %old_hash;
my %last_name = (
'Yu' => 'bo',
'He' => 'chun',
);
foreach my $first (qw <Yu He>) {
print "$first in @last_name{$first}.\n";
}
上面的hash赋值完后还可以使用 $hash{“d”} = 1; 的方式解决。 还有一种方式可以赋值:
my %last_name;
$last_name{"fred"} = "hehe";
$last_name{"yubo"} = "bo";
$last_name{"he"} = "chun";
注意,赋值的时候使用%,使用的时候却是$
下面这句话改变了 key 和 value 的位置。
my %inverse_hash = reverse %any_hash;
my %hash = ('a' => 1, 'b' => 2, 'c' => 3);
my @k = keys %hash;
my @v = values %hash;
foreach (@k) {
print "$_\n";
}
这样就会打印hash的key,但是有一点请注意,perl不保证输出的顺序, 也就是你最好不要期望得到你想要的顺序。又但是,keys 和 values函数 可以保证此时的值相对应,例如,上面的例子@k会打印出c b a,那么打印 的@v一定是3 1 2
There is another function:
my $count = keys %hash;
$count的值就是hash函数中的对数。
while ( ($key, $value) = each %hash) {
print "$key => $value\n";
}
After sorted hash
foreach $key (sort keys %hash) {
$value = $hash{$key};
print "$key => $value\n";
}
The exists Function,to see whether a key exists in the hash, use the exists function,if true
以上面的代码为例:
if (exists $hash{"a"}) {
print "Hey, there exist\n";
}
if (!exists $hash{"d"}) {
print "NO exist!\n";
}
不知道我的思路是否有问题,$hash,@hash,%hash三者之间有着某种联系, 虽说hash是用来定义的,但它仅仅是定义吗?在其他的外部调用中,我们 反而使用的是$hash{“”},在当时学习@hash和$hash也有同样的问题。
print "PATH is $ENV{path}\n";
write a perl file, output the times of that have read from terminal. For example, input “yubo,hechun,yubo,hechun” output the numbers”yubo 2…hechun 2”
my(@words, %count, $word); # declare
chomp(@words = <STDIN>); # input
foreach $word (@words) {
$count{$word} += 1;
}
foreach $word (keys %count) {
print "$word was seen $count{$word} time . \n";
}
自己从这个程序中稍微理解了hash的原理,其中最后一个比较有意思, 在count hash中$word作为keys,so the value is $count{$word}.
下面的例子与上面的很类似
$longest = 0;
foreach my $key (keys %ENV) {
my $key_long = length($key);
$longest = $key_long if $key_long > $longest;
}
foreach my $key (sort keys %ENV) {
printf "%-s{longest} %s \n.$key, $ENV{$key}";
}