接触过内核的朋友肯定在源码中看到许多.S文件,这些文件中基本都是汇编。
这些文件是干什么的,为什么要这么写? Continue reading »
最近调程序,出现illegal instruction问题,没有头绪。 索性把illegal instruction好好窥探一下。 Continue reading »
start_kernel is the first function that kernel runs, like the main function in user space program.
In this post, I will try to get a detailed understand of how start_kernel is called on X86_64 and MIPS architecture. Continue reading »
系统复杂了,什么毛病都会出,最近在使用Gentoo和Debian的过程中,都出现了其他程序能正常使用ibus输入法,偏偏Emacs不能的情况。
不过最终都被征服了。解决方案放在这里,备查。
- 英文系统中使用ibus。中文系统请无视。英文系统emacs需要设置locale的支持。
不管是Gentoo还是Debian,如果无法正确调出ibus输入法,即ibus不能将emacs识别为输入窗口,请检查环境变量LC_CTYPE是否为zh_CN.utf8.
可以使用如下命令,执行emacs。至少经过这一步,ibus就能将emacs识别为输入窗口了。
$LC_CTYPE=zh_CN.utf8 emacs ##或者直接增加一个小脚本启动emacs #!/bin/sh export LC_CTYPE=zh_CN.utf8 /usr/bin/emacs $*
- 在emacs中,ibus有输入框,能显式备选汉字,但无法输入到emacs界面中。我在Gentoo和Debian中都遇到了这个问题。
Gentoo: 当时按照参考1,稀里糊涂的安装了几个字体之后问题解决。
[ebuild N ] media-fonts/font-adobe-75dpi-1.0.0 USE="X nls" 0 kB [ebuild N ] x11-apps/bdftopcf-1.0.2 USE="-debug" 0 kB [ebuild N ] media-fonts/font-alias-1.0.1 USE="-debug" 0 kB [ebuild N ] media-fonts/font-util-1.1.1 USE="-debug" 0 kB
Debian: 若在Debian上采用英文系统,多半不能自动增加中文的locale,就是因为没有中文的locale。执行如下命令,增加对zh_CN.utf8 locale的支持即可。
$ sudo dpkg-reconfigure locales
- 若以上方案都不能解决你的问题,那推荐你试试Ibus Mode 。
很多时候,会有人建议你,如果kill杀不掉一个进程,就用kill -9. 为什么?
kill是Linux下常见的命令。其man手册的功能定义如下:
kill – send a signal to a process
明朗了,其实kill就是给某个进程id发送了一个信号。默认发送的信号是SIGTERM,而kill -9发送的信号是SIGKILL,即exit。exit信号不会被系统阻塞,所以kill -9能顺利杀掉进程。当然你也可以使用kill发送其他信号给进程。
经常使用的killall呢?
killall – kill processes by name
即,通过指定进程名的方式杀死进程。
注:这篇文章只是说说bash在命令行中的正则匹配(globbing),而非SHELL编程中的正则表达式展开(regular expression expansion,regex).相关源码在bash/subst.c中。感谢khsing的指正。
我们知道Bash的命令行支持正则表达式,而有些命令也支持正则表达式。问题来了,对于下面的操作:
$ls Makefile*
谁负责正则表达式展开呢?
拿出我们的万能工具strace。在本博的某个文件夹下运行,可以看到如下不同:
$strace ls Makefile*
execve("/bin/ls", ["ls", "Makefile", "Makefile.cross", "Makefile.gsetup"], [/* 66 vars */]) = 0
brk(0) = 0x8060000
$strace ls Makefile
execve("/bin/ls", ["ls", "Makefile"], [/* 66 vars */]) = 0
brk(0) = 0x8060000
Bash在execve运行/bin/ls程序的时候,已经展开了。所以Shell负责了ls的正则表达式展开。
又有个有趣的问题,Bash如何实现这种正则展开的,又如何判断要针对哪些程序做正则展开呢?Bash的Man手册里有这样一段话:
* Matches anystring, including the null string. When the globstar shell option is enabled, and * is used in a pathname expansion context, twoadjacent *s used as a single pattern will match all files and zero or more directories and subdirectories. If followed by a /,two adjacent *s will match only directories and subdirectories.
翻译如下:
* 匹配任何字符串,包括空串。如果打开Shell的globstar选项, 单个*用于路径名称展开,相邻的两个*用于匹配所有在当前和所有子文件夹中的文件。如果在两个*之后有/,那么两个*仅匹配文件夹和子文件夹。
所以上面的问题就解决了。Bash仅展开正则表达式用于匹配文件名,所有的程序在操作文件时都可使用这种表达式。展开的方式就靠特定的规则。
因此上面ls Makefile*时,bash会展开文件名,传给execve的就是完整的三个被展开的文件了。
忽然想起另一个有趣的问题,比如下面的内容:
ls sdfafa
ls: cannot access sdfafa: No such file or directory
很显然,当前目录下没有这个文件,所以报错。既然Bash能展开正则表达式,那么 ls sdfafa的这个错误提示是谁个的? ls sdfafa*的正则表达式要展开吗?
上strace,如下:
$strace ls sdfafa
execve("/bin/ls", ["ls", "sdfafa"], [/* 66 vars */]) = 0
brk(0) = 0x8060000
$strace ls sdfafa*
execve("/bin/ls", ["ls", "sdfafa*"], [/* 66 vars */]) = 0
brk(0) = 0x8060000
可见,Bash并没有展开这个正则表达式。可以断定,当当前目录下没有匹配的文件时,就不展开,直接传入。错误是由ls程序给出的。
如何避免Bash的正则展开呢?转移字符’\'即可。
Bash编程,或者在bashrc中,我们经常会通过export VAR=XXXX的形式来设置环境变量。其实在shell中,也可以直接VAR=XXX的形式来设置。在shell中执行这两个语句,都会将VAR设置为XXX,你可以通过echo来验证,那么这两个又有什么区别呢? Continue reading »
这个问题已经有点老生常谈了。这里简单记录一下。
库调用
- 通常调用的是代码库中的函数,如GLIBC,LIBGCC,LIBSTDC++,BOOST之类的库
- 这些库函数会和程序链接,静态链和动态链都可以
- 仅仅在用户态,即用户地址空间內执行
- 多数为了避免程序员重复劳动,封装复杂编码或者性能提升
系统调用
- 由操作系统提供的一类函数
- 提供操作系统才能实现的服务
- 函数主要在内核态,即内核地址空间內执行。
- 因为牵涉到内核态和用户态的切换问题,通常调用代价大。
通常这两者的概念区别并不明显,有些库函数也会内部封装系统调用,比如printf。
参考:
Segmentation Fault是常见的程序错误,错误原因说白了就是访问了不该访问的内存。什么是不该访问的内存,操作系统如何判断哪些内存该哪些程序访问呢?
什么是不该访问的内存:出segmentation fault的情景,都应该是因为访问了不该访问的内存。包括:访问的地址不属于进程地址空间、访问的类型是否符合该内存区域类型。进程地址空间的判定方式,本博会在日后文章中再讲。先说说内存区域的访问类型问题。下面一张图给出了Segmentation fault引发的大致机制。图来自参考1的总结文档。
linux/include/mm.h中定义了一块内存可以允许的访问类型,包括四种,如下:
#define VM_READ 0x00000001
#define VM_WRITE 0x00000002
#define VM_EXEC 0x00000004
#define VM_SHARED 0x00000008
有四种类型,可读,可写,可执行,共享内存。另外这个头文件里还规定了很多其他属性,先略去不看。这四种属性是最基本的。具体的作用就不做说明了。这样的处理,可以保证内存是安全的,内核可以给数据的读写权限,给代码段执行权限,给共享库或者多线程下的全局数据共享属性。而且内核可以控制这些属性的变化。比如JIT,在程序执行过程中,把一段程序编译所得的代码,先以数据的方式存在内存中,再将这块内存设置为可执行,就可以直接执行了。不设置为可执行,就仅仅是一段存在内存中的机器码而已。
还有一个问题,虽然内存有这些属性,但他们肯定是相对于某个进程而言的,且不同的进程,这些属性也不同。这些是在哪里规定的呢?等日后再深挖
参考:
- http://bbs3.chinaunix.net/viewthread.php?tid=1632005&extra=page%3D1%26amp;filter%3Ddigest&page=1
- Understanding Linux Kernel 3ed, P355
一个程序在终端运行时,我们可以CTRL+C退出该程序或者CTRL+Z暂时停止该程序。那么有办法屏蔽这两个操作吗?
首先,得明白CTRL+C和CTRL+Z做了些什么。stty是Linux下的命令,输出和设置命令行控制参数。stty -a能输出所有命令行设置。如下是本博的命令行设置:
$stty -a可以看到CTRL+C就等于INTR,CTRL+Z就是SUSP,也就是说这两个分别会向程序发送SIGINT和SIGSTOP信号,这两个信号,一个用于终止进程,一个用于暂停进程,即挂起。
speed 38400 baud; rows 48; columns 159; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = M-^?; eol2 = M-^?; swtch = M-^?; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W;
lnext = ^V; flush = ^O; min = 1; time = 0;
-parenb -parodd cs8 hupcl -cstopb cread -clocal -crtscts
-ignbrk brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc ixany imaxbel iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke
信号是Linux系统用于进程间通信的,内核也可以通过它们向程序发送消息。这些信号都很小,Sponge Liu写了篇文章《Linux内核信号处理机制介绍》,深入浅出的走了介绍。
接下来的问题就是,如何屏蔽两个信号。当然,你也可以通过设置stty的方式实现。可以在程序中屏蔽吗?如果可以,如何屏蔽?如果不可以,为啥?
很明显,肯定有些信号不能被屏蔽,比如中断,还应该有杀死进程的信号,要不然内核怎么做操作系统中的老大。实际上,SIGKILL和SIGSTOP信号是不能被屏蔽或阻止的,他们的默认动作总是会被执行的。
那就来个程序,直接屏蔽SIGINT信号吧.
#include
#include
#include
#include
#include
bool keep_going = true;
void ignore_notice()
{
keep_going=false;
printf("recieved SIGINT,and ignore it.\n");
}
void do_something()
{
int i=0;
while(i < 1000000)
{
i++;
}
}
int main ()
{
if(signal(SIGINT, ignore_notice) == SIG_ERR)
{
printf("Fail\n");
return 1;
}
while(keep_going)
do_something();
printf("program normally exit.\n");
return 0;
}
下面语句设置针对SIGINT的动作,第二个参数可以传入函数指针,指定处理方式为函数内容,也可以为SIG_IGN,忽略这个信号,或者SIG_DFL,执行默认的动作。
signal(SIGINT, ignore_notice) == SIG_ERR
参考:


近期评论