随笔分类 -  Linux Programming

摘要:1、为什么会出现系统调用被中断的情况? 进程在执行一个低速系统调用而阻塞期间捕捉到一个信号时,该系统调用就被中断不再继续执行。该系统调用返回出错,其errno被设置为EINTR。这样处理的理由是:因为一个信号发生了,进程捕捉到了它,这意味着已经发生了某种事情,所以是个唤醒阻塞的系统调用的好机会。2... 阅读全文
posted @ 2014-03-02 13:16 在于思考 阅读(1118) 评论(0) 推荐(0) 编辑
摘要:brk和sbrk的定义 在man手册中定义了这两个函数:1 #include 2 int brk(void *addr);3 void *sbrk(intptr_t increment); 手册上说brk和sbrk会改变programbreak的位置,programbreak被定义为程序datasegment的结束位置。感觉这句话不是很好理解,从下面程序地址空间的分布来看,datasegment后面还有bsssegment,显然和手册说的不太一样。一种可能的解释就是手册中的datasegment和下图中的datasegment不是一个意思,手册中的datasegment应该包含了下图中的d.. 阅读全文
posted @ 2014-02-25 14:46 在于思考 阅读(15123) 评论(5) 推荐(3) 编辑
摘要:为什么需要标准IO缓冲? LINUX用缓冲的地方遍地可见,不管是硬件、内核还是应用程序,内核里有页高速缓冲,内存高速缓冲,硬件更不用说的L1,L2cache,应用程序更是多的数不清,基本写的好的软件都有。但归根结底这些缓冲的作用是相同的,都是为了提高机器或者程序的性能。而需要缓冲大部分的情况都是为了协调两个设备或者两个系统间速度的不匹配。 大家都知道IO设备的访问速度与CPU的速度相差好几个数量级,所以为了协调IO设备与CPU的速度的不匹配,对于块设备内核使用了页高速缓存。也就是说,数据会先被拷贝到操作系统内核的页缓存区中,然后才会从操作系统内核的缓存区拷贝到应用程序的地址空间。 当应用... 阅读全文
posted @ 2014-02-24 18:36 在于思考 阅读(3404) 评论(0) 推荐(0) 编辑
摘要:遍历目录的主要思想 由于目录就是一颗树,所以遍历目录就转换为遍历一棵树。谈到树的遍历就再熟悉不过了,有树的前序、层次和后序遍历,我使用的是前序遍历,后序遍历和前序遍历本质上一样,而层次遍历要比前两个麻烦些,我两个都实现了,现在贴出来分享下。前序遍历 前序遍历和树的遍历一样,我先显示当前目录的信息,然后遍历目录中的目录项,如果目录项是一个目录则先递归这个子目录,否则如果是目录项是非目录的话就返回。 1 static void DoTraverDir(MyFunc myFunc) 2 { 3 struct stat statBuf; 4 DIR *pDir; 5 str... 阅读全文
posted @ 2014-02-24 11:26 在于思考 阅读(4234) 评论(0) 推荐(2) 编辑
摘要:为什么要使用动态链接? 在现代的linux系统中,假设一个普通的程序会使用到c语言静态库至少1MB以上,那么,如果我们的机器运行100个这样的程序,就用浪费近100MB的内存;如果磁盘有2000个这样的程序,就要浪费2GB的内存。 静态链接对程序的更新、发布等也会带来问题。比如程序program1使 阅读全文
posted @ 2013-12-19 15:58 在于思考 阅读(1410) 评论(0) 推荐(0) 编辑
摘要:链接器在根据命令行中输入的可重定位目标文件和静态库的顺序从左到右的扫描这些文件。在这个扫描中,链接器会维护一个集合E,该集合包含了将来要被合并生产可执行文件的所有可重定位目标文件;维护了一个集合U,包含了未解决的符号(只引用了但还没有定义);还维护了一个集合D,包含被先前输入文件定义的符号。开始的时候这三个集合都为空。对于在命令行中的每个输入文件f,链接器都会去判断这个文件是目标文件还是静态库文件。如果是目标文件,链接器将f加入到集合E中,并将f中的已定义的符号和引用的符号分别加入到集合D和U中,并继续处理下一个文件。如果f是静态库文件,链接器会扫描静态库中的目标文件m,如果m中定义的符号.. 阅读全文
posted @ 2013-12-19 10:20 在于思考 阅读(882) 评论(0) 推荐(0) 编辑
摘要:一直对ELF目标文件是怎样链接成可执行文件感到比较的疑惑,ELF文件里面的重定位段是怎样解决符号引用问题的?前几天偶然看了《深入理解计算机系统》里面讲了这个问题,看了之后对里面的实现机制终于有了一定的理解。 当有链接器链接多个可重定位的共享对象时,共享对象时怎样合并的呢?很简单,链接器将相同类型的节合并在一起,比如将所有输入文件的.text合并到输出文件的.text段,接着是.data段,.bss段等。 链接器扫描所有的输入目标文件,并且获得它们各个节的长度,属性和位置,并将输入目标文件中的符号表中所有的符号定义和符号引用收集起来,统一放到一个全局符号表中。链接器能够获得所有输入目标文... 阅读全文
posted @ 2013-12-18 11:18 在于思考 阅读(1962) 评论(0) 推荐(1) 编辑
摘要:1 ELF文件结构 图中显示了ELF可重定位文件的构成,ELF文件头的开始16个字节描述了文件中字的大小和字节序(大端模式还是小端模式)。文件头还包含了ELF头的大小,文件类型(可重定位,可执行和共享),机器类型,节头表的位置和大小。节头表中的每项对应于文件中的一个节,用于描述节的位置和大小。 ELF文件头: ELF头对应的代码定义为:#define EI_NIDENT 16typedef struct elf32_hdr{ unsigned char e_ident[EI_NIDENT]; //开始的16个字节 Elf32_Half e_type; //文件类... 阅读全文
posted @ 2013-12-14 19:50 在于思考 阅读(3857) 评论(0) 推荐(3) 编辑
摘要:在编写简单的c运行库(二)中主要实现了对有关文件操作函数的实现,接下来主要实现有关字符串的函数,如itoa,strcmp,strcpy,strlen函数,这些函数并没有用到系统调用,所以也就不用向实现文件操作的函数那样使用内嵌汇编,这些函数的定义都放在string.h中。实现了字符串函数之后,就大概实现了一个小型的c运行库,虽然很简略,但对于理解c库函数运行原理、所用的关键技术有了比较深刻的认识。最后用这个小的c运行库来编译运行一个简单的测试程序,用以测试我们的库能否正常的工作。1 字符串函数 字符串函数中主要是实现itoa函数有点难度,其它的都还比较的简单,所以这里主要讲下itoa函数... 阅读全文
posted @ 2013-06-07 22:19 在于思考 阅读(1439) 评论(0) 推荐(2) 编辑
摘要:在前面编写简单的c运行库(一)中主要实现了调用main函数前的初始化、获取参数和环境变量、退出程序等工作。接下来我们真正实现c标准库中的一些函数(主要是文件操作、字符串操作函数)。不过我们对这些函数的实现力争简单,对于效率方面考虑的不是很多,因为目的主要还是学习神秘的库是怎么实现的。1 文件操作 c中的标准I/O库都是带有缓存的,我们在这里为了实现的简单,将缓存省略了,直接包装了有关文件操作的系统调用。现在我们直接看文件打开的函数: 1 static int open(const char *pathname, int flags, int mode) 2 { 3 int ret... 阅读全文
posted @ 2013-06-07 08:56 在于思考 阅读(1394) 评论(0) 推荐(0) 编辑
摘要:1 进程相关ID 除了进程ID外,与进行相关的ID主要有六个:实际用户ID、实际组ID、有效用户ID、有效组ID、附加组ID、保存的设置用户ID、保存的设置组ID。实际用户ID和实际组ID标识进程是属于谁的。这两个字段在登入时取自口令文件中的登入项。有效用户ID,有效组ID以及附加组ID决定了进程对文件的访问权限。保存的设置用户ID和保存的设置组ID在执行一个程序时包含了有效用户ID和有效组ID的副本。 通常在执行一个程序文件时,进程的有效用户ID通常就是实际用户ID,有效组ID就是实际组ID。在文件模式st_mode中设置一个特殊的标志,其含义是“当执行文件时,将进程的有效用户ID设置为.. 阅读全文
posted @ 2013-06-06 20:55 在于思考 阅读(520) 评论(0) 推荐(0) 编辑
摘要:看了《程序员自我修养》这本书后,对目标文件、可执行文件的结构有了比较清晰的了解,对目标文件链接成可执行文件的过程和程序运行库有了大致的认识。不过正如“纸上得来终觉浅,绝知此事需恭行”,很多东西看似容易,但实践的时候却往往不是这样,在实践中往往能发现很多的问题。《程序员自我修养》这本书我觉得是理论与实践很好的结合了,它在最后一章给出了一个c和c++运行库的简单版的实现,通过实现这个可以更为深刻地理解可执行文件的结构、程序的执行、运行库的实现。参考这边书,我在linux下实现的一个简单的c运行库,这个运行库主要实现了文件操作、字符串操作、动态内存分配三个方面。1 程序的入口函数实现 当被问到... 阅读全文
posted @ 2013-06-05 21:10 在于思考 阅读(1487) 评论(2) 推荐(2) 编辑
摘要:最近有个项目需要生成静态编译的可执行文件,以便在其它linux的机器中运行,开始以为非常简单,直接在编译中加个-static选项不就是了,结果却和我想的太不一样了,下面说下我遇到的问题以及解决的方法。 开始按照设想应该只要在编译中加个-static选项就可以了,不过却报下面的错误: cc -g -s 阅读全文
posted @ 2013-05-11 18:23 在于思考 阅读(11036) 评论(0) 推荐(0) 编辑
摘要:对于一个程序员来说,调试是很重要的,可以节约找到bug的时间,不过以前在linux下一直是对c进行调试的,今天突然要对汇编进行调试还真不知道怎么调,特别是对linux下调试汇编程序基本没搞过。记得以前上课学masm时,用的是debug,貌似映像中对汇编挺难调试的。于是就在网上查了下在linux下调试nasm汇编程序的资料,看起来比debug简单点。1 写和编译源文件 首先准备个hello.asm文件,这个学语言必编的程序,代码如下: section .datamsg: db "hello, world", 10len equ $-msg section .text ... 阅读全文
posted @ 2013-04-23 16:23 在于思考 阅读(4230) 评论(1) 推荐(3) 编辑
摘要:我实现的文件监控主要是对某个文件夹里所有的文件检测是否修改、是否有新建文件、是否有文件被删除,并把这些改变记录到文件中。开始想用链表存储文件信息,毕竟链表删除方便,但链表的查找效率不高,所以打算用红黑树实现,因为红黑树查找和删除的操作都是比较快的。 基本思路是这样的:对于指定的文件夹,首先调用一个扫描函数,扫描指定文件夹里的所有文件和文件夹,当遇到一个文件或文件夹时,用文件名作为关键字在红黑树中查找该文件,如果不存在,就把文件名作为关键字,将文件路径,文件修改时间,标记等信息存入一个结点插入到红黑树中,将标记设置为新插入,如果存在,由于找到的结点会有多个(同名文件),所以要比较所有找到结... 阅读全文
posted @ 2013-04-10 09:42 在于思考 阅读(1771) 评论(3) 推荐(1) 编辑
摘要:红黑树的定义和插入在红黑树的实现(一)中已经描述和实现了,下面说一下红黑树的删除。 红黑树的删除也包括两个步骤: 1.删除结点 2.调整树满足红黑树的定义 首先是删除一个结点,同样可以按二叉排序树的删除结点来删除。删除结点又分为4中情况: (1)删除结点没有左孩子,有右孩子 (2)删除结点没有右孩子,有左孩子 (3)删除结点为叶子结点 (4)删除结点既有左孩子又有右孩子 对于情况(1),可以直接用右孩子代替删除的结点,并且由于删除结点有右孩子,所以删除结点必定为黑色,右孩子必定为红色(假设删除结点为红色,右孩子必定为黑色,这样是违反红黑树定义4的,所以删除结点必定为黑色,... 阅读全文
posted @ 2013-04-09 20:20 在于思考 阅读(1194) 评论(0) 推荐(1) 编辑
摘要:由于看个东西,发现要用到红黑树,所以拿算法导论看了下红黑树的定义和实现,第一遍看发现红黑树挺复杂的,第二遍再看发现好了点,第三遍又好点。。。n遍之后终于有点理解了。最后打算自己实现这个红黑树,也能更好的理解它。1 红黑色定义 首先红黑树的定义是非常重要的,它的定义如下: 1.一个结点要么是黑色,要么是红色,只能是其中的一种。 2.树的根结点一定是黑色。 3.如果一个结点为红色,那么它的孩子结点必定为黑色。 4.从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点。 正是有了这个定义,使得红黑树保持了良好的性质,如树的高度不会超过2lgn,所以对某个关键字的查找时间为o(... 阅读全文
posted @ 2013-04-09 17:00 在于思考 阅读(1647) 评论(4) 推荐(1) 编辑