<?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>不然你要我怎么样 &#187; Embedded</title>
	<atom:link href="http://www.xiangmocheng.com/category/embedded/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.xiangmocheng.com</link>
	<description>彪悍的代码不需要注释</description>
	<lastBuildDate>Wed, 30 Nov 2011 11:47:45 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>【转贴】GCC编译器选项及优化提示</title>
		<link>http://www.xiangmocheng.com/2009/12/gcc-compiler-options-and-optimization-tips/</link>
		<comments>http://www.xiangmocheng.com/2009/12/gcc-compiler-options-and-optimization-tips/#comments</comments>
		<pubDate>Thu, 17 Dec 2009 15:01:07 +0000</pubDate>
		<dc:creator>xiangmocheng</dc:creator>
				<category><![CDATA[Embedded]]></category>
		<category><![CDATA[GCC]]></category>

		<guid isPermaLink="false">http://www.xiangmocheng.com/?p=69572</guid>
		<description><![CDATA[大多数程序和库在编译时默认的优化级别是”2&#8243;(使用gcc选项:”-O2&#8243;)并且在Intel/AMD平台上默认按照i386处理器来编译。如果你只想让编译出来的程序运行在特定的平台上，就需要执行更高级的编译器优化选项，以产生只能运行于特定平台的代码。 一种方法是修改每个源码包中的Makefile文件，在其中寻找CFLAGS和CXXFLAGS变量(C和C++编译器的编译选项)并修改它的值。一些源码包比如binutils, gcc, glibc等等，在每个子文件夹中都有Makefile文件，这样修改起来就太累了！ 另一种简易做法是设置CFLAGS和CXXFLAGS环境变量。大多数configure脚本会使用这两个环境变量代替Makefile文件中的值。但是少数configure脚本并不这样做，他们必须需要手动编辑才行。 为了设置CFLAGS和CXXFLAGS环境变量，你可以在bash中执行如下命令(也可以写进.bashrc以成为默认值)： export CFLAGS=”-O3 -march=” &#038;&#038; CXXFLAGS=$CFLAGS 这是一个确保能够在几乎所有平台上都能正常工作的最小设置。 “-march”选项表示为特定的cpu类型编译二进制代码(不能在更低级别的cpu上运行)，Intel通常是：pentium2, pentium3, pentium3m, pentium4, pentium4m, pentium-m, prescott, nocona 说明：pentium3m/pentium4m是笔记本用的移动P3/P4；pentium-m是迅驰I/II代笔记本的cpu；prescott是带SSE3的P4(以滚烫到可以煎鸡蛋而闻名)；nocona则是最新的带有EMT64(64位)的P4(同样可以煎鸡蛋) AMD通常是：k6, k6-2, k6-3, athlon, athlon-tbird, athlon-xp, athlon-mp, opteron, athlon64, athlon-fx 用AMD的一般都是DIYer，就不必解释了吧。 如果编译时没有抱怨”segmentation fault, core dumped”，那么你设定的”-O”优化参数一般就没什么问题。否则请降低优化级别(“-O3&#8243; -> “-O2&#8243; -> “-O1&#8243; -> 取消)。 个人意见：服务器使用”-O2&#8243;就可以了，它是最安全的优化参数(集合)；桌面可以使用”-O3&#8243; ；不鼓励使用过多的自定义优化选项，其实他们之间没什么明显的速度差异(有时”-O3&#8243;反而更慢)。 编译器对硬件非常敏感，特别是在使用较高的优化级别的时候，一丁点的内存错误都可能导致致命的失败。所以在编译时请千万不要超频你的电脑(我编译关键程序时总是先降频然的)。 注意：选项的顺序很重要，如果有两个选项互相冲突，则以后一个为准。比如”-O3&#8243;将打开-finline-functions选项，但是可以用”-O3 -fno-inline-functions”既使用-O3的功能又关闭函数内嵌功能。 更多的优化选项请参见： http://gcc.gnu.org/onlinedocs/gcc-3.4.4/gcc/Optimize-Options.html http://gcc.gnu.org/onlinedocs/gcc-3.4.4/gcc/i386-and-x86_002d64-Options.html http://gcc.gnu.org/onlinedocs/gcc-4.0.2/gcc/Optimize-Options.html http://gcc.gnu.org/onlinedocs/gcc-4.0.2/gcc/i386-and-x86_002d64-Options.html 所有GCC选项完整列表参见： http://gcc.gnu.org/onlinedocs/gcc-3.4.4/gcc/Option-Summary.html http://gcc.gnu.org/onlinedocs/gcc-4.0.2/gcc/Option-Summary.html [...]]]></description>
			<content:encoded><![CDATA[<p>大多数程序和库在编译时默认的优化级别是”2&#8243;(使用gcc选项:”-O2&#8243;)并且在Intel/AMD平台上默认按照i386处理器来编译。如果你只想让编译出来的程序运行在特定的平台上，就需要执行更高级的编译器优化选项，以产生只能运行于特定平台的代码。</p>
<p>一种方法是修改每个源码包中的Makefile文件，在其中寻找CFLAGS和CXXFLAGS变量(C和C++编译器的编译选项)并修改它的值。一些源码包比如binutils, gcc, glibc等等，在每个子文件夹中都有Makefile文件，这样修改起来就太累了！</p>
<p>另一种简易做法是设置CFLAGS和CXXFLAGS环境变量。大多数configure脚本会使用这两个环境变量代替Makefile文件中的值。但是少数configure脚本并不这样做，他们必须需要手动编辑才行。</p>
<p>为了设置CFLAGS和CXXFLAGS环境变量，你可以在bash中执行如下命令(也可以写进.bashrc以成为默认值)：<br />
export CFLAGS=”-O3 -march=<cpu类型>” &#038;&#038; CXXFLAGS=$CFLAGS<br />
这是一个确保能够在几乎所有平台上都能正常工作的最小设置。</p>
<p>“-march”选项表示为特定的cpu类型编译二进制代码(不能在更低级别的cpu上运行)，Intel通常是：pentium2, pentium3, pentium3m, pentium4, pentium4m, pentium-m, prescott, nocona<br />
说明：pentium3m/pentium4m是笔记本用的移动P3/P4；pentium-m是迅驰I/II代笔记本的cpu；prescott是带SSE3的P4(以滚烫到可以煎鸡蛋而闻名)；nocona则是最新的带有EMT64(64位)的P4(同样可以煎鸡蛋)<br />
AMD通常是：k6, k6-2, k6-3, athlon, athlon-tbird, athlon-xp, athlon-mp, opteron, athlon64, athlon-fx<br />
用AMD的一般都是DIYer，就不必解释了吧。</p>
<p>如果编译时没有抱怨”segmentation fault, core dumped”，那么你设定的”-O”优化参数一般就没什么问题。否则请降低优化级别(“-O3&#8243; -> “-O2&#8243; -> “-O1&#8243; -> 取消)。<br />
个人意见：服务器使用”-O2&#8243;就可以了，它是最安全的优化参数(集合)；桌面可以使用”-O3&#8243; ；不鼓励使用过多的自定义优化选项，其实他们之间没什么明显的速度差异(有时”-O3&#8243;反而更慢)。</p>
<p>编译器对硬件非常敏感，特别是在使用较高的优化级别的时候，一丁点的内存错误都可能导致致命的失败。所以在编译时请千万不要超频你的电脑(我编译关键程序时总是先降频然的)。</p>
<p>注意：选项的顺序很重要，如果有两个选项互相冲突，则以后一个为准。比如”-O3&#8243;将打开-finline-functions选项，但是可以用”-O3 -fno-inline-functions”既使用-O3的功能又关闭函数内嵌功能。</p>
<p><span id="more-69572"></span></p>
<p>更多的优化选项请参见：</p>
<p>http://gcc.gnu.org/onlinedocs/gcc-3.4.4/gcc/Optimize-Options.html</p>
<p>http://gcc.gnu.org/onlinedocs/gcc-3.4.4/gcc/i386-and-x86_002d64-Options.html</p>
<p>http://gcc.gnu.org/onlinedocs/gcc-4.0.2/gcc/Optimize-Options.html</p>
<p>http://gcc.gnu.org/onlinedocs/gcc-4.0.2/gcc/i386-and-x86_002d64-Options.html</p>
<p>所有GCC选项完整列表参见：</p>
<p>http://gcc.gnu.org/onlinedocs/gcc-3.4.4/gcc/Option-Summary.html</p>
<p>http://gcc.gnu.org/onlinedocs/gcc-4.0.2/gcc/Option-Summary.html</p>
<p>有两个页面值的参考：<br />
(对于gentoo-1.4)比较安全的优化选项</p>
<p>http://www.freehackers.org/gentoo/gccflags/flag_gcc3.html</p>
<p>(对于gentoo-1.4)进阶优化选项</p>
<p>http://www.freehackers.org/gentoo/gccflags/flag_gcc3opt.html</p>
<p>*******************************************************************</p>
<p>哦，忘了说一声，”-O2&#8243;已经启用绝大多数安全的优化选项了，所以其实你不必对那一堆选项发愁。<br />
先说说”-O3&#8243;在”-O2&#8243;基础上增加的几项，你可以按需添加(还算比较安全)：<br />
[gcc-3.4.4]<br />
-finline-functions 允许编译器选择某些简单的函数在其被调用处展开<br />
-fweb 为每个web结构体分配一个伪寄存器<br />
-frename-registers 试图驱除代码中的假依赖关系，这个选项对具有大量寄存器的机器很有效。<br />
[gcc-4.0.2]<br />
-finline-functions 说明如上<br />
-funswitch-loops 将循环体中不改变值的变量移动到循环体之外<br />
-fgcse-after-reload **不太明白它的含义**[哪位大峡知道给小弟讲解一下，先行谢过 ]</p>
<p>说完”-O3&#8243;再说说在嵌入式系统上常用的”-Os”选项，这个选项其实也很重要，它的含义是对生成的二进制代码进行尺寸上的优化，它打开了所有”-O2&#8243;打开的选项，因此通常认为的”-Os”生成的二进制代码执行效率低的潜在意识是错误的！当然该选项与”-O2&#8243;的不同之处在于它在”-O2&#8243; 的基础上禁止了所有为了对齐而插入的空间，也就是将所有”-falign-*”系列的选项禁用了。这种禁用究竟是否一定降低了代码的执行效率，依据程序的不同而不同，据说某些情况下”-Os”的效率比”-O3&#8243;还要高14%！请兄弟们在实践中自己摸索吧&#8230;</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</p>
<p>下面选择我认为比较重要的几项简单介绍一下[gcc-3.4.4]，GCC选项完整列表太长了！精力有限。<br />
[注意]这里列出的都是非默认的选项，你只需要添加你所需要的选项即可</p>
<p>-w 禁止输出警告消息</p>
<p>-Werror 将所有警告转换为错误</p>
<p>-Wall 显示所有的警告消息</p>
<p>-v 显示编译程序的当前版本号</p>
<p>-V<version> 指定gcc将要运行的版本。只有在安装了多个版本gcc的机器上才有效。</p>
<p>-ansi 按照ANSI标准编译程序，但并不限制与标准并不冲突的GNU扩展(一般不用该选项)</p>
<p>-pedantic 如果要限制代码必须严格符合ISO标准，就在”-ansi”的基础上同时启用这个选项(很少使用)</p>
<p>-std=<name> 指定C语言的标准(c89,c99,gnu89)，该选项禁止了GNU C的扩展关键字asm,typeof,inline (一般不用该选项)</p>
<p>-static 连接器将忽略动态连接库，同时通过将静态目标文件直接包含到结果目标文件完成对所有引用的解析。</p>
<p>-shared 连接器将生成共享目标代码，该共享库可在运行时动态连接到程序形成完整的可执行体。<br />
如果使用gcc命令创建共享库作为其输出，该选项可以防止连接器将缺失main()方法视为错误。<br />
为了可以正确的工作，应该一致的使用选项”-fpic”以及目标平台选项编译构成同一个库的所有共享目标模块。</p>
<p>-shared-libgcc 该选项指定使用共享版本的libgcc，在没有共享版本的libgcc的机器上该选项无效。</p>
<p>-specs=<filename> gcc驱动程序读取该文件以确定哪些选项应该传递给那些子进程。<br />
该选项可以通过指定配置文件来覆盖默认配置，指定的文件将在默认配置文件读取后进行处理以修改默认配置。</p>
<p>-pipe 使用管道而不是临时文件一个阶段到另一个阶段交换输出的方式，可以加快编译速度。建议使用。</p>
<p>-o <filename> 指定输出文件，对各种输出皆有效。由于只能指定一个文件，所以在产生多个输出文件的情况下不要使用该选项。</p>
<p>&#8211;help 显示gcc的命令行选项列表；与”-v”一起使用时还将显示gcc调用的各个进程所接受的选项。</p>
<p>&#8211;target-help 显示目标机器相关的命令行选项列表</p>
<p>-b<machine> 指示需要编译程序的目标机器；默认为编译程序所运行的目标机编译代码。<br />
目标机通过指定包含编译程序的目录来确定，通常为/usr/local/lib/gcc-lib/<machine>/<version></p>
<p>-B
<lib-prefix> 指定库文件的位置，包括编译程序的文件、执行程序和数据文件，如果需要运行子程序(如cpp,as,ld)就会用该前缀来定位。<br />
这个前缀可以是用冒号分割的多个路径，环境变量GCC_EXEC_PREFIX和这个选项有相同的效果。</p>
<p>-I<dir> 指定搜索系统头文件的目录，可以重复使用多个该选项指定多个目录。</p>
<p>-dumpmachine 显示该程序的目标机名字，不做其他任何动作</p>
<p>-dumpspecs 显示构件编译程序的规范信息，包括用来编译、汇编和连接gcc编译程序自身用到的所有选项，不做其他任何动作。</p>
<p>-dumpversion 显示编译程序自身的版本号，不做其他任何动作</p>
<p>-falign-functions=N 将所有函数的起始地址在N(N=1,2,4,8,16&#8230;)的边界上对齐，默认为机器自身的默认值，指定为1表示禁止对齐。</p>
<p>-falign-jumps=N 将分支目标在N(N=1,2,4,8,16&#8230;)的边界上对齐，默认为机器自身的默认值，指定为1表示禁止对齐。<br />
-fno-align-labels 建议使用它，以保证不和-falign-jumps(“-O2&#8243;默认启用的选项)冲突</p>
<p>-fno-align-loops 建议使用它，以确保不会在分支目标前插入多余的空指令。</p>
<p>-fbranch-probabilities 在使用”-fprofile-arcs”选项编译程序并执行它来创建包含每个代码块执行次数的文件之后，程序可以利用这一选项再次编译，<br />
文件中所产生的信息将被用来优化那些经常发生的分支代码。如果没有这些信息，gcc将猜测那一分支可能经常发生并进行优化。<br />
这类优化信息将会存放在一个以源文件为名字的并以”.da”为后缀的文件中。</p>
<p>-fno-guess-branch-probability 默认情况下gcc将使用随机模型进行猜测哪个分支更可能被经常执行，并以此来优化代码，该选项关闭它。</p>
<p>-fprofile-arcs 在使用这一选项编译程序并运行它以创建包含每个代码块的执行次数的文件后，程序可以再次使用”-fbranch-probabilities”编译，<br />
文件中的信息可以用来优化那些经常选取的分支。如果没有这些信息，gcc将猜测哪个分支将被经常运行以进行优化。<br />
这类优化信息将会存放在一个以源文件为名字的并以”.da”为后缀的文件中。</p>
<p>-fforce-addr 必须将地址复制到寄存器中才能对他们进行运算。由于所需地址通常在前面已经加载到寄存器中了，所以这个选项可以改进代码。<br />
-fforce-mem 必须将数值复制到寄存器中才能对他们进行运算。由于所需数值通常在前面已经加载到寄存器中了，所以这个选项可以改进代码。</p>
<p>-ffreestanding 所编译的程序能够在独立的环境中运行，该环境可以没有标准库，而且可以不从main()函数开始运行。<br />
该选项将设置”-fno-builtin”，且等同于”-fno-hosted”。<br />
-fhosted 所编译的程序需要运行在宿主环境中，其中需要有完整的标准库，而且main()函数具有int型的返回值。<br />
-fno-builtin 除非利用”__builtin_”进行引用，否则不识别所有内建函数。</p>
<p>-fmerge-all-constants 试图将跨编译单元的所有常量值和数组合并在一个副本中。但是标准C/C++要求每个变量都必须有不同的存储位置。</p>
<p>-fmove-all-movables 将所有不变的表达式移动到循环体之外，这种做法的好坏取决于源代码中的循环结构。</p>
<p>-fnon-call-exceptions 产生的代码可供陷阱指令(如非法浮点运算和非法内存寻址)抛出异常，需要相关平台的运行时支持，并不普遍有效。</p>
<p>-fomit-frame-pointer 对于不需要栈指针的函数就不在寄存器中保存指针，因此可以忽略存储和检索地址的代码，并将寄存器用于普通用途。<br />
所有”-O”级别都打开着一选项，但仅在调试器可以不依靠栈指针运行时才有效。建议不需要调试的情况下显式的设置它。</p>
<p>-fno-optional-diags 禁止输出诊断消息，C++标准并不需要这些消息。<br />
-fpermissive 将代码中与标准不符合的诊断消息作为警告而不是错误输出。</p>
<p>-fpic 生成可用于共享库的位置独立代码(PIC)，所有的内存寻址均通过全局偏移表(GOT)完成。该选项并非在所有的机器上都有效。<br />
要确定一个地址，需要将代码自身的内存位置作为表中的一项插入。该选项可以产生在共享库中存放并从中加载的目标模块。</p>
<p>-fprefetch-loop-arrays 生成数组预读取指令，对于使用巨大数组的程序可以加快代码执行速度，适合数据库相关的大型软件等。</p>
<p>-freg-struct-return 生成用寄存器返回短结构的代码，如果寄存器无法荣纳将使用内存。</p>
<p>-fstack-check 为防止程序栈溢出而进行必要的检测，在多线程环境中运行时才可能需要它。</p>
<p>-ftime-report 编译完成后显示编译耗时的统计信息</p>
<p>-funroll-loops 如果在编译时可以确定迭代的次数非常少而且循环中的指令也非常少，可以使用该选项进行循环展开，以驱除循环和复制指令。</p>
<p>-finline-limit=<size> 对伪指令数超过<size>的函数，编译程序将不进行展开，默认为600</p>
<p>&#8211;param <name>=<value> gcc内部存在一些优化代码程度的限制，调整这些限制就是调整整个优化全局。下面列出了参数的名字和对应的解释：<br />
名字 解释<br />
max-delay-slot-insn-search 较大的数目可以生成更优化的代码，但是会降低编译速度，默认为100<br />
max-delay-slot-live-search 较大的数目可以生成更优化的代码，但是会降低编译速度，默认为333<br />
max-gcse-memory 执行GCSE优化使用的最大内存量，太小将使该优化无法进行，默认为50M<br />
max-gcse-passes 执行GCSE优化的最大迭代次数，默认为1</p>
<p>*******************************************************************<br />
说完了命令行选项，下面来说说与硬件体系结构(主要是cpu)相关的设置[仅针对i386/x86_64]<br />
最大名鼎鼎的”-march”上面已经说过了，下面讲讲别的(仅挑些实用的)</p>
<p>-mfpmath=sse P3和athlon-tbird以上级别的cpu支持</p>
<p>-masm=<dialect> 使用指定的dialect输出汇编语言指令，可以使用”intel”或”att”；默认为”att”</p>
<p>-mieee-fp 指定编译器使用IEEE浮点比较，这样将会正确的处理比较结果为无序的情况。</p>
<p>-malign-double 将double, long double, long long对齐于双字节边界上；有助于生成更高速的代码，但是程序的尺寸会变大。</p>
<p>-m128bit-long-double 指定long double为128位，pentium以上的cpu更喜欢这种标准。</p>
<p>-mregparm=N 指定用于传递整数参数的寄存器数目(默认不使用寄存器)。0<=N<=3 ；注意：当N>0时你必须使用同一参数重新构建所有的模块，包括所有的库。</p>
<p>-mmmx<br />
-mno-mmx<br />
-msse<br />
-mno-sse<br />
-msse2<br />
-mno-sse2<br />
-msse3<br />
-mno-sse3<br />
-m3dnow<br />
-mno-3dnow<br />
上面的这些不用解释了，一看就明白，根据自己的CPU决定吧</p>
<p>-maccumulate-outgoing-args 指定在函数引导段中计算输出参数所需最大空间，这在大部分现代cpu中是较快的方法；缺点是会增加代码尺寸。</p>
<p>-mthreads 支持Mingw32的线程安全异常处理。对于依赖于线程安全异常处理的程序，必须启用这个选项。<br />
使用这个选项时会定义”-D_MT”，它将包含使用选项”-lmingwthrd”连接的一个特殊的线程辅助库，用于为每个线程清理异常处理数据。</p>
<p>-minline-all-stringops 嵌入所有的字符串操作。可以提高字符串操作的性能，但是会增加代码尺寸。</p>
<p>-momit-leaf-frame-pointer 不为叶子函数在寄存器中保存栈指针，这样可以节省寄存器，但是将会是调试变的困难。参见”-fomit-frame-pointer”。</p>
<p>下面这几个仅用于x86_64环境：</p>
<p>-m64 生成专门运行于64位环境的代码，不能运行于32位环境</p>
<p>-mcmodel=small [默认值]程序和它的符号必须位于2GB以下的地址空间。指针仍然是64位。程序可以静态连接也可以动态连接。<br />
-mcmodel=kernel 内核运行于2GB地址空间之外。在编译linux内核时必须使用该选项！<br />
-mcmodel=medium 程序必须位于2GB以下的地址空间，但是它的符号可以位于任何地址空间。程序可以静态连接也可以动态连接。<br />
注意：共享库不能使用这个选项编译！<br />
-mcmodel=large 对地址空间没有任何限制，这个选项的功能目前尚未实现。</p>
<p>＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝<br />
既然已经讲了这么多了索性再讲讲gcc使用的一些环境变量<br />
除了大名鼎鼎的CFLAGS和CXXFLAGS以外(其实是Autoconf的环境变量)，再挑几个说说：<br />
所有的PATH类环境变量(除LD_RUN_PATH外)都是用冒号分割的目录列表。</p>
<p>C_INCLUDE_PATH 编译C程序时使用的环境变量，用于查找头文件。</p>
<p>CPLUS_INCLUDE_PATH 编译C++程序时使用的环境变量，用于查找头文件。</p>
<p>OBJC_INCLUDE_PATH 编译Obj-C程序时使用的环境变量，用于查找头文件。</p>
<p>CPATH 编译C/C++/Obj-C程序时使用的环境变量，用于查找头文件。</p>
<p>COMPILER_PATH 如果没有用GCC_EXEC_PREFIX定位子程序，编译程序将会在此查找它的子程序。</p>
<p>LIBRARY_PATH 连接程序将在这些目录中寻找特殊的连接程序文件。</p>
<p>LD_LIBRARY_PATH 该环境变量不影响编译程序，但是程序运行的时候会有影响：程序会查找该目录列表以寻找共享库。<br />
当不能够在编译程序的目录中找到共享库的时候，执行程序必须设置该环境变量。</p>
<p>LD_RUN_PATH 该环境变量不影响编译程序，但是程序运行的时候会有影响：它在运行时指出了文件的名字，运行的程序可以由此得到它的符号名字和地址。<br />
由于地址不会重新载入，因而可能符号应用其他文件中的绝对地址。这个和ld工具使用的”-R”选项完全一样。</p>
<p>GCC_EXEC_PREFIX 编译程序执行所有子程序的名字的前缀，默认值是”
<prefix>/lib/gcc-lib/”，<br />
其中的
<prefix>是安装时configure脚本指定的前缀。</p>
<p>LANG 指定编译程序使用的字符集，可用于创建宽字符文件、串文字、注释；默认为英文。[目前只支持日文"C-JIS,C-SJIS,C-EUCJP"，不支持中文]</p>
<p>LC_ALL 指定多字节字符的字符分类，主要用于确定字符串的字符边界以及编译程序使用何种语言发出诊断消息；默认设置与LANG相同。<br />
中文相关的几项：”zh_CN.GB2312 , zh_CN.GB18030 , zh_CN.GBK , zh_CN.UTF-8 , zh_TW.BIG5&#8243;</p>
<p>TMPDIR 编译程序存放临时工作文件的临时目录，这些临时文件通常在编译结束时被删除。</p>
<p>===============================================</p>
<p>作者：金步国<br />
原帖来自：http://www.linuxsir.org/bbs/showthread.php?t=222670
<div style="margin-top: 10px">
<p><strong>转载请注明：</strong> 转载自<a href="http://www.xiangmocheng.com/">不然你要我怎么样</a></t>        </br><strong>本文链接地址:</strong> <a href="http://www.xiangmocheng.com/2009/12/gcc-compiler-options-and-optimization-tips/">【转贴】GCC编译器选项及优化提示</a></div>
]]></content:encoded>
			<wfw:commentRss>http://www.xiangmocheng.com/2009/12/gcc-compiler-options-and-optimization-tips/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>【转贴】Linux输出信息调试信息重定向</title>
		<link>http://www.xiangmocheng.com/2009/12/how-to-redirect-linux-debug-message/</link>
		<comments>http://www.xiangmocheng.com/2009/12/how-to-redirect-linux-debug-message/#comments</comments>
		<pubDate>Tue, 01 Dec 2009 08:07:08 +0000</pubDate>
		<dc:creator>xiangmocheng</dc:creator>
				<category><![CDATA[Embedded]]></category>
		<category><![CDATA[Kernel]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[UART]]></category>

		<guid isPermaLink="false">http://xiangmocheng.yo2.cn/articles/%e3%80%90%e8%bd%ac%e8%b4%b4%e3%80%91linux%e8%be%93%e5%87%ba%e4%bf%a1%e6%81%af%e8%b0%83%e8%af%95%e4%bf%a1%e6%81%af%e9%87%8d%e5%ae%9a%e5%90%91.html</guid>
		<description><![CDATA[在运行linux的时候，所有的调试信息可以分为三个部分 1. bootloader输出信息 U-Boot 1.3.2 (Nov 19 2016 &#8211; 22:02:08) DRAM: 64 MB Flash: 512 kB NAND: 64 MiB In: serial Out: serial Err: serial Hit any key to stop autoboot: 0 [yqliu2410 #] tftp Found DM9000 ID:90000a46 at address 10000000 ! DM9000 work in 16 bus width bd-&#62;bi_entaddr: 08:00:3e:26:0a:5b [eth_init]MAC:8:0:3e:26:a:5b: TFTP from server 192.168.1.152; [...]]]></description>
			<content:encoded><![CDATA[<p>在运行linux的时候，所有的调试信息可以分为三个部分</p>
<p>1. bootloader输出信息</p>
<p>U-Boot 1.3.2 (Nov 19 2016 &#8211; 22:02:08)<br />
DRAM: 64 MB<br />
Flash: 512 kB<br />
NAND: 64 MiB<br />
In: serial<br />
Out: serial<br />
Err: serial<br />
Hit any key to stop autoboot: 0<br />
[yqliu2410 #] tftp<br />
Found DM9000 ID:90000a46 at address 10000000 !<br />
DM9000 work in 16 bus width<br />
bd-&gt;bi_entaddr: 08:00:3e:26:0a:5b<br />
[eth_init]MAC:8:0:3e:26:a:5b:<br />
TFTP from server 192.168.1.152; our IP address is 192.168.1.155<br />
Filename &#8216;uImage&#8217;.<br />
Load address: 0&#215;30008000<br />
Loading: TT##################################done<br />
Bytes transferred = 1617316 (18ada4 hex)<br />
[up-tech2410 #] bootm<br />
## Booting image at 30008000 &#8230;<br />
Image Name: Linux-2.6.24.4<br />
Created: 2016-11-19 14:05:29 UTC<br />
Image Type: ARM Linux Kernel Image (uncompressed)<br />
Data Size: 1617252 Bytes = 1.5 MB<br />
Load Address: 30008000<br />
Entry Point: 30008040<br />
Verifying Checksum &#8230; OK<br />
Starting kernel &#8230;</p>
<p><span id="more-69493"></span></p>
<p>2. linux低级调试信息输出</p>
<p>Uncompressing Linux&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;.. done, booting the kernel.</p>
<p>3. linux调试信息输出</p>
<p style="margin: 5px; line-height: 150%;">Linux version 2.6.24.4 (root@vm-dev) (gcc version 3.4.6) #100 Sat Nov 19 07:47:35 CST 2016<br />
CPU: ARM920T [41129200] revision 0 (ARMv4T), cr=00007177<br />
Machine: SMDK2410<br />
Memory policy: ECC disabled, Data cache writeback<br />
CPU S3C2410A (id 0&#215;32410002)<br />
S3C2410: core 202.800 MHz, memory 101.400 MHz, peripheral 50.700 MHz<br />
S3C24XX Clocks, (c) 2004 Simtec Electronics</p>
<p style="margin: 5px; line-height: 150%;">&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;.</p>
<p>现在要将所有的调试信息输出到别的串口。以com1为例(从com0开始计算)</p>
<p>一、将bootloader的输出信息输出到com1</p>
<p>这里以u-boot1.3.2为例：很简单只需要修改一个宏定义就ok</p>
<p>Vi inlcude/configs/xxxconfig.h(xxx为你定义的开发板的名字)</p>
<p>更改原有的宏</p>
<table style="border-collapse: collapse;" border="1" cellspacing="0" cellpadding="0" width="95%" bgcolor="#f1f1f1" bordercolor="#999999">
<tbody>
<tr>
<td>
<p style="margin: 5px; line-height: 150%;"><code><span style="color: #000000;">/<span style="color: #0000cc;">*</span><br />
<span style="color: #0000cc;">*</span> select serial console configuration<br />
<span style="color: #0000cc;">*</span><span style="color: #0000cc;">/</span><br />
//#define CONFIG_SERIAL1 1 /<span style="color: #0000cc;">*</span> we use SERIAL 1 on SMDK2410 <span style="color: #0000cc;">*</span><span style="color: #0000cc;">/</span><br />
//modify <span style="color: #0000ff;">for</span> xxx2410<br />
//by lyj_uptech<br />
#define CONFIG_SERIAL2 1 /<span style="color: #0000cc;">*</span> we use SERIAL 2 on SMDK2410 <span style="color: #0000cc;">*</span><span style="color: #0000cc;">/</span></span></code></p>
</td>
</tr>
</tbody>
</table>
<p>二、将low_level 的调试信息输出到com1</p>
<p>在改之前我们先分析一下在linux启动之前它是如何使用串口的（以linux-2.6.24为例）。</p>
<p>1. 在arch/arm/boot/compressed/misc.c文件中有定义</p>
<table style="border-collapse: collapse;" border="1" cellspacing="0" cellpadding="0" width="95%" bgcolor="#f1f1f1" bordercolor="#999999">
<tbody>
<tr>
<td>
<p style="margin: 5px; line-height: 150%;"><code><span style="color: #000000;"><span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span> putstr<span style="color: #0000cc;">(</span><span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span> <span style="color: #0000cc;">*</span>ptr<span style="color: #0000cc;">)</span><br />
<span style="color: #0000cc;">{</span><br />
<span style="color: #0000ff;">char</span> c<span style="color: #0000cc;">;</span><br />
<span style="color: #0000ff;">while</span> <span style="color: #0000cc;">(</span><span style="color: #0000cc;">(</span>c <span style="color: #0000cc;">=</span> <span style="color: #0000cc;">*</span>ptr<span style="color: #0000cc;">+</span><span style="color: #0000cc;">+</span><span style="color: #0000cc;">)</span> <span style="color: #0000cc;">!</span><span style="color: #0000cc;">=</span> <span style="color: #ff00ff;">'\0'</span><span style="color: #0000cc;">)</span> <span style="color: #0000cc;">{</span><br />
<span style="color: #0000ff;">if</span> <span style="color: #0000cc;">(</span>c <span style="color: #0000cc;">=</span><span style="color: #0000cc;">=</span> <span style="color: #ff00ff;">'\n'</span><span style="color: #0000cc;">)</span><br />
<span style="color: #ff0000;">putc</span><span style="color: #0000cc;">(</span><span style="color: #ff00ff;">'\r'</span><span style="color: #0000cc;">)</span><span style="color: #0000cc;">;</span><br />
<span style="color: #ff0000;">putc</span><span style="color: #0000cc;">(</span>c<span style="color: #0000cc;">)</span><span style="color: #0000cc;">;</span><br />
<span style="color: #0000cc;">}</span><br />
<span style="color: #ff0000;">flush</span><span style="color: #0000cc;">(</span><span style="color: #0000cc;">)</span><span style="color: #0000cc;">;</span><br />
<span style="color: #0000cc;">}</span></span></code></p>
<p style="margin: 5px; line-height: 150%;">
</td>
</tr>
</tbody>
</table>
<p>2. arch/arm/boot/compressed/misc.中的函数decompress_kernel就是使用的putstr来打印的如下输出信息：</p>
<table style="border-collapse: collapse;" border="1" cellspacing="0" cellpadding="0" width="95%" bgcolor="#f1f1f1" bordercolor="#999999">
<tbody>
<tr>
<td>
<p style="margin: 5px; line-height: 150%;"><code><span style="color: #000000;">Uncompressing Linux<span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span><span style="color: #0000cc;">.</span> done<span style="color: #0000cc;">,</span> booting the kernel</span></code></p>
</td>
</tr>
</tbody>
</table>
<p>3. 追根溯源，putstr函数最终调用的是putc（请注意这里的putc不是在misc.c函数中定义的icedcc_putc，因为没有CONFIG_CPU_V6宏定义），真正的底层操作在文件include/asm-arm/plat-s3c/uncompress.h</p>
<p>4. 解析该文件</p>
<table style="border-collapse: collapse;" border="1" cellspacing="0" cellpadding="0" width="95%" bgcolor="#f1f1f1" bordercolor="#999999">
<tbody>
<tr>
<td>
<p style="margin: 5px; line-height: 150%;"><code><span style="color: #000000;"><span style="color: #ff9900;">/* we can deal with the case the UARTs are being run<br />
* in FIFO mode, so that we don't hold up our execution<br />
* waiting for tx to happen...<br />
*/</span><br />
<span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span> <span style="color: #ff0000;">putc</span><span style="color: #0000cc;">(</span><span style="color: #0000ff;">int</span> ch<span style="color: #0000cc;">)</span><br />
<span style="color: #0000cc;">{</span><br />
<span style="color: #0000ff;">if</span> <span style="color: #0000cc;">(</span>uart_rd<span style="color: #0000cc;">(</span>S3C2410_UFCON<span style="color: #0000cc;">)</span> <span style="color: #0000cc;">&amp;</span> S3C2410_UFCON_FIFOMODE<span style="color: #0000cc;">)</span> <span style="color: #0000cc;">{</span><br />
<span style="color: #0000ff;">int</span> level<span style="color: #0000cc;">;</span><br />
<span style="color: #0000ff;">while</span> <span style="color: #0000cc;">(</span>1<span style="color: #0000cc;">)</span> <span style="color: #0000cc;">{</span><br />
level <span style="color: #0000cc;">=</span> uart_rd<span style="color: #0000cc;">(</span>S3C2410_UFSTAT<span style="color: #0000cc;">)</span><span style="color: #0000cc;">;</span><br />
level <span style="color: #0000cc;">&amp;</span><span style="color: #0000cc;">=</span> fifo_mask<span style="color: #0000cc;">;</span></span></code></p>
<p><span style="color: #0000ff;">if</span> <span style="color: #0000cc;">(</span>level <span style="color: #0000cc;">&lt;</span> fifo_max<span style="color: #0000cc;">)</span><br />
<span style="color: #0000ff;">break</span><span style="color: #0000cc;">;</span><br />
<span style="color: #0000cc;">}</span><br />
<span style="color: #0000cc;">}</span> <span style="color: #0000ff;">else</span> <span style="color: #0000cc;">{</span><br />
<span style="color: #ff9900;">/* not using fifos */</span><br />
<span style="color: #0000ff;">while</span> <span style="color: #0000cc;">(</span><span style="color: #0000cc;">(</span>uart_rd<span style="color: #0000cc;">(</span>S3C2410_UTRSTAT<span style="color: #0000cc;">)</span> <span style="color: #0000cc;">&amp;</span> S3C2410_UTRSTAT_TXE<span style="color: #0000cc;">)</span> <span style="color: #0000cc;">!</span><span style="color: #0000cc;">=</span> S3C2410_UTRSTAT_TXE<span style="color: #0000cc;">)</span><br />
barrier<span style="color: #0000cc;">(</span><span style="color: #0000cc;">)</span><span style="color: #0000cc;">;</span><br />
<span style="color: #0000cc;">}</span><br />
<span style="color: #ff9900;">/* write byte to transmission register */</span><br />
uart_wr<span style="color: #0000cc;">(</span>S3C2410_UTXH<span style="color: #0000cc;">,</span> ch<span style="color: #0000cc;">)</span><span style="color: #0000cc;">;</span><br />
<span style="color: #0000cc;">}</span></p>
<p style="margin: 5px; line-height: 150%;">
</td>
</tr>
</tbody>
</table>
<p>该函数中调用的两个函数，uart_rd uart_wr在同一个文件中定义</p>
<table style="border-collapse: collapse;" border="1" cellspacing="0" cellpadding="0" width="95%" bgcolor="#f1f1f1" bordercolor="#999999">
<tbody>
<tr>
<td>
<p style="margin: 5px; line-height: 150%;"><code><span style="color: #000000;"><span style="color: #0000cc;">#</span><span style="color: #ff0000;">define</span> uart_base S3C24XX_PA_UART <span style="color: #0000cc;">+</span> <span style="color: #0000cc;">(</span>0x4000<span style="color: #0000cc;">*</span>CONFIG_S3C_LOWLEVEL_UART_PORT<span style="color: #0000cc;">)</span><br />
<span style="color: #0000ff;">static</span> <span style="color: #0000ff;">__inline__</span> <span style="color: #0000ff;">void</span><br />
uart_wr<span style="color: #0000cc;">(</span><span style="color: #0000ff;">unsigned</span> <span style="color: #0000ff;">int</span> reg<span style="color: #0000cc;">,</span> <span style="color: #0000ff;">unsigned</span> <span style="color: #0000ff;">int</span> val<span style="color: #0000cc;">)</span><br />
<span style="color: #0000cc;">{</span><br />
<span style="color: #0000ff;">volatile</span> <span style="color: #0000ff;">unsigned</span> <span style="color: #0000ff;">int</span> <span style="color: #0000cc;">*</span>ptr<span style="color: #0000cc;">;</span><br />
ptr <span style="color: #0000cc;">=</span> <span style="color: #0000cc;">(</span><span style="color: #0000ff;">volatile</span> <span style="color: #0000ff;">unsigned</span> <span style="color: #0000ff;">int</span> <span style="color: #0000cc;">*</span><span style="color: #0000cc;">)</span><span style="color: #0000cc;">(</span>reg <span style="color: #0000cc;">+</span> uart_base<span style="color: #0000cc;">)</span><span style="color: #0000cc;">;</span><br />
<span style="color: #0000cc;">*</span>ptr <span style="color: #0000cc;">=</span> val<span style="color: #0000cc;">;</span><br />
<span style="color: #0000cc;">}</span><br />
<span style="color: #0000ff;">static</span> <span style="color: #0000ff;">__inline__</span> <span style="color: #0000ff;">unsigned</span> <span style="color: #0000ff;">int</span><br />
uart_rd<span style="color: #0000cc;">(</span><span style="color: #0000ff;">unsigned</span> <span style="color: #0000ff;">int</span> reg<span style="color: #0000cc;">)</span><br />
<span style="color: #0000cc;">{</span><br />
<span style="color: #0000ff;">volatile</span> <span style="color: #0000ff;">unsigned</span> <span style="color: #0000ff;">int</span> <span style="color: #0000cc;">*</span>ptr<span style="color: #0000cc;">;</span><br />
ptr <span style="color: #0000cc;">=</span> <span style="color: #0000cc;">(</span><span style="color: #0000ff;">volatile</span> <span style="color: #0000ff;">unsigned</span> <span style="color: #0000ff;">int</span> <span style="color: #0000cc;">*</span><span style="color: #0000cc;">)</span><span style="color: #0000cc;">(</span>reg <span style="color: #0000cc;">+</span> uart_base<span style="color: #0000cc;">)</span><span style="color: #0000cc;">;</span><br />
<span style="color: #0000ff;">return</span> <span style="color: #0000cc;">*</span>ptr<span style="color: #0000cc;">;</span><br />
<span style="color: #0000cc;">}</span></span></code></p>
<p style="margin: 5px; line-height: 150%;">
</td>
</tr>
</tbody>
</table>
<p>从宏定义uart_base中就可以清楚的看到，当CONFIG_S3C_LOWLEVEL_UART_PORT为0时,uart_base的值为0&#215;50000000,也就是uart0的控制寄存器基地址。如果要使用uart1的话就把CONFIG_S3C_LOWLEVEL_UART_PORT赋值为1就可以了。</p>
<p>5、真正更改的地方只有一个</p>
<p><img src="http://blogimg.chinaunix.net/blog/upfile2/081120131415.jpg" border="0" alt="" /></p>
<p>下级目录</p>
<p><img src="http://blogimg.chinaunix.net/blog/upfile2/081120132127.jpg" border="0" alt="" /></p>
<p>修改为1就ok！</p>
<p>6. 需要注意的地方（你使用的串口初始化了么）</p>
<p>我在整个内核中找遍了解压内核之前运行的代码，都找不到关于串口初始化的代码。所以说，linux在启动之前的串口初始化是依赖bootloader的，要想正常的输出，就必须使用你的bootloader使用的串口，因为在bootloader中进行了对要使用的串口进行了初始化。要保证你的bootloader兼容性很好，那就在bootloader中把所有的串口都初始化一遍。</p>
<p>如果你没有初始化串口，一旦调用putstr，程序就死掉了！</p>
<p>三、将linux的信息输出到com1</p>
<p>将linux运行的信息输出到com1就太简单了，直接到bootloader里面改linux的传递参数就可以了。</p>
<table style="border-collapse: collapse;" border="1" cellspacing="0" cellpadding="0" width="95%" bgcolor="#f1f1f1" bordercolor="#999999">
<tbody>
<tr>
<td>
<p style="margin: 5px; line-height: 150%;"><code><span style="color: #000000;">setenv bootargs root<span style="color: #0000cc;">=</span><span style="color: #0000cc;">/</span>dev<span style="color: #0000cc;">/</span>mtdblock2 noinitrd console<span style="color: #0000cc;">=</span>ttySAC1<span style="color: #0000cc;">,</span>115200<br />
saveenv</span></code></p>
</td>
</tr>
</tbody>
</table>
<p>现在启动一切ok！</p>
<p>感谢yqliu29的支持，没有他的调试程序，我始终的无法知道linux的内核是否正确调用，也无法定位问题！</p>
<p>这里附上他给我的程序（这里的三个灯分别对应的io管脚是 GPF5/6/7）</p>
<table style="border-collapse: collapse;" border="1" cellspacing="0" cellpadding="0" width="95%" bgcolor="#f1f1f1" bordercolor="#999999">
<tbody>
<tr>
<td>
<p style="margin: 5px; line-height: 150%;"><code><span style="color: #000000;">#<span style="color: #0000ff;">if</span> 0<br />
asm volatile<span style="color: #0000cc;">(</span><br />
<span style="color: #ff00ff;">"ldr r6, =0x5400\n\r"</span><br />
<span style="color: #ff00ff;">"ldr r7, =0x56000020\n\r"</span><br />
<span style="color: #ff00ff;">"str r6, [r7]\n\r"</span><br />
<span style="color: #ff00ff;">"ldr r6, =0xC0\n\r"</span><br />
<span style="color: #ff00ff;">"ldr r7, =0x56000024\n\r"</span><br />
<span style="color: #ff00ff;">"str r6, [r7]"</span><span style="color: #0000cc;">)</span><span style="color: #0000cc;">;</span><br />
#<span style="color: #0000ff;">endif</span></span></code></p>
</td>
</tr>
</tbody>
</table>
<p>原帖地址：http://blog.chinaunix.net/u1/57747/showart_1432451.html
<div style="margin-top: 10px">
<p><strong>转载请注明：</strong> 转载自<a href="http://www.xiangmocheng.com/">不然你要我怎么样</a></t>        </br><strong>本文链接地址:</strong> <a href="http://www.xiangmocheng.com/2009/12/how-to-redirect-linux-debug-message/">【转贴】Linux输出信息调试信息重定向</a></div>
]]></content:encoded>
			<wfw:commentRss>http://www.xiangmocheng.com/2009/12/how-to-redirect-linux-debug-message/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>【转贴】代码优化－之－优化除法</title>
		<link>http://www.xiangmocheng.com/2009/09/code-optimization-division/</link>
		<comments>http://www.xiangmocheng.com/2009/09/code-optimization-division/#comments</comments>
		<pubDate>Wed, 23 Sep 2009 01:16:58 +0000</pubDate>
		<dc:creator>xiangmocheng</dc:creator>
				<category><![CDATA[Embedded]]></category>

		<guid isPermaLink="false">http://xiangmocheng.yo2.cn/articles/%e3%80%90%e8%bd%ac%e8%b4%b4%e3%80%91%e4%bb%a3%e7%a0%81%e4%bc%98%e5%8c%96%ef%bc%8d%e4%b9%8b%ef%bc%8d%e4%bc%98%e5%8c%96%e9%99%a4%e6%b3%95.html</guid>
		<description><![CDATA[(说明：文章中的很多数据可能在新的CPU或不同的CPU或不同的系统环境下有不同的结果，可能不能面面俱到) x86系列的CPU对于位运算、加、减等基本指令都能在1个CPU周期内完成(现在的CPU还能乱序执行，从而使指令的平均CPU周期更小)；现在的CPU,做乘法也是很快的(1个CPU周期左右，或者是需要两\三个周期，但每个周期能启动一个新的乘指令)，但作为基本指令的除法却超出很多人的预料，它是一条很慢的操作，整数和浮点的除法都慢；我测试的英特尔P5赛扬CPU浮点数的除法差不多是37个CPU周期，整数的除法是80个CPU周期，AMD2200+浮点数的除法差不多是21个CPU周期，整数的除法是40个CPU周期。(改变FPU运算精度对于除法无效) (SSE指令集的低路单精度数除法指令DIVPS 18个CPU周期,四路单精度数除法指令DIVSS 36个CPU周期) (x86求余运算和除法运算是用同一条CPU指令实现的； 据说，很多CPU的整数除法都是用数学协处理器的浮点除法器完成的；有一个推论就是，浮点除法和整数除法不能并行执行) 本文将给出一些除法的优化方法或替代算法 (警告:某些替代算法并不能保证完全等价!) 1.尽量少用除法 比如： if (x/y&#62;z) &#8230; 改成： if ( ((y&#62;0)&#38;&#38;(x&#62;y*z))&#124;&#124;((y&#60;0)&#38;&#38;(x (少用求余) 比如： ++index; if (index&#62;=count) index=index % count; //assert(index 改成： ++index; if (index&#62;=count) index=index &#8211; count; 2.用减法代替除法 如果知道被除数是除数的很小的倍数，那么可以用减法来代替除法 比如： uint32 x=200; uint32 y=70; uint32 z=x/y; 改成： uint z=0; while (x&#62;=y) { x-=y; ++z; } 一个用减法和移位完成的除法 (如果你没有除法指令可用:) uint32 [...]]]></description>
			<content:encoded><![CDATA[<p>(说明：文章中的很多数据可能在新的CPU或不同的CPU或不同的系统环境下有不同的结果，可能不能面面俱到)</p>
<p>x86系列的CPU对于位运算、加、减等基本指令都能在1个CPU周期内完成(现在的CPU还能乱序执行，从而使指令的平均CPU周期更小)；现在的CPU,做乘法也是很快的(1个CPU周期左右，或者是需要两\三个周期，但每个周期能启动一个新的乘指令)，但作为基本指令的除法却超出很多人的预料，它是一条很慢的操作，整数和浮点的除法都慢；我测试的英特尔P5赛扬CPU浮点数的除法差不多是37个CPU周期，整数的除法是80个CPU周期，AMD2200+浮点数的除法差不多是21个CPU周期，整数的除法是40个CPU周期。(改变FPU运算精度对于除法无效) (SSE指令集的低路单精度数除法指令DIVPS 18个CPU周期,四路单精度数除法指令DIVSS 36个CPU周期) (x86求余运算和除法运算是用同一条CPU指令实现的； 据说，很多CPU的整数除法都是用数学协处理器的浮点除法器完成的；有一个推论就是，浮点除法和整数除法不能并行执行)</p>
<p>本文将给出一些除法的优化方法或替代算法 (警告:某些替代算法并不能保证完全等价!)</p>
<p><span id="more-69476"></span></p>
<p>1.尽量少用除法</p>
<p>比如： if (x/y&gt;z) &#8230;</p>
<p>改成： if ( ((y&gt;0)&amp;&amp;(x&gt;y*z))||((y&lt;0)&amp;&amp;(x</p>
<p>(少用求余)</p>
<p>比如： ++index; if (index&gt;=count) index=index % count; //assert(index</p>
<p>改成： ++index; if (index&gt;=count) index=index &#8211; count;</p>
<p>2.用减法代替除法</p>
<p>如果知道被除数是除数的很小的倍数，那么可以用减法来代替除法</p>
<p>比如： uint32 x=200;</p>
<p>uint32 y=70;</p>
<p>uint32 z=x/y;</p>
<p>改成： uint z=0;</p>
<p>while (x&gt;=y)</p>
<p>{</p>
<p><span style="white-space: pre;"> </span>x-=y; ++z;</p>
<p>}</p>
<p>一个用减法和移位完成的除法 (如果你没有除法指令可用:)</p>
<p>uint32 div(uint64 s,uint32 z) //return u/z</p>
<p>{</p>
<p>uint32 x=(uint32)(s&gt;&gt;32);</p>
<p>uint32 y=(uint32)s;</p>
<p>//y保存商 x保存余数</p>
<p>for (int i=0;i&lt;32;++i)</p>
<p>{</p>
<p>uint32 t=((int32)x) &gt;&gt; 31;</p>
<p>x=(x&lt;&lt;1)|(y&gt;&gt;31);</p>
<p>y=y&lt;&lt;1;</p>
<p>if ((x|t)&gt;=z)</p>
<p>{</p>
<p>x-=z;</p>
<p>++y;</p>
<p>}</p>
<p>}</p>
<p>return y;</p>
<p>}</p>
<p>(该函数经过了测试；z==0需要自己处理；对于有符号除法，可以用取绝对值的方法(当然也不是轻松就能</p>
<p>写出完全等价的有符号除法的:)； 如果不需s的64bit长度，仅需要32bit,那么可以化简这个函数，但改进不多)</p>
<p>3.用移位代替除法 (很多编译器能自动做好这个优化)</p>
<p>要求除数是2的次方的常量； (同理：对于某些应用，可以优先选取这样的数来做除数)</p>
<p>比如： uint32 x=213432575;</p>
<p> uint32 y=x/8;</p>
<p>改成： y=x&gt;&gt;3;</p>
<p>对于有符号的整数；</p>
<p>比如： int32 x=213432575;</p>
<p> int32 y=x/8;</p>
<p>改成： if (x&gt;=0) y=x&gt;&gt;3;</p>
<p>else y=(x+(1&lt;&lt;3-1))&gt;&gt;3;</p>
<p>4.合并除法 (替代方法不等价，很多编译器都不会(而且不应该)帮你做这种优化)</p>
<p>适用于不能用其它方法避免除法的时候；</p>
<p>比如： double x=a/b/c;</p>
<p>改成： double x=a/(b*c);</p>
<p>比如： double x=a/b+c/b;</p>
<p>改成： double x=(a+c)/b;</p>
<p>比如： double x=a/b;</p>
<p>double y=c/d;</p>
<p>double z=e/f;</p>
<p>改成： double tmp=1.0/(b*d*f);</p>
<p>double x=a*tmp*d*f;</p>
<p>double y=c*tmp*b*f;</p>
<p>double z=e*tmp*b*d;</p>
<p>5.把除法占用的时间充分利用起来</p>
<p>CPU在做除法的时候，可以不用等待该结果(也就是后面插入的指令不使用该除法结果)，而插入多条简单整数</p>
<p>指令(不包含整数除法，而且结果不能是一个全局或外部变量等)，把除法占用的时间节约出来；</p>
<p>(当除法不可避免的时候，这个方法很有用)</p>
<p>6.用查表的方法代替除法</p>
<p>（适用于除数和被除数的可能的取值范围较小的情况，否则空间消耗太大）</p>
<p>比如 uint8 x; uint8 y;</p>
<p> uint8 z=x/y;</p>
<p>改成 uint8 z=table[x][y]; //其中table是预先计算好的表，table[i][j]=i/j;</p>
<p>//对于除零的情况需要根据你的应用来处理</p>
<p>或者：uint8 z=table[x&lt;&lt;8+y]; //其中table[i]=(i&gt;&gt;8)/(i&amp;(1&lt;&lt;8-1));</p>
<p>比如 uint8 x;</p>
<p> uint8 z=x/17;</p>
<p>改成 uint8 z=table[x]; //其中table[i]=i/17;</p>
<p>7.用乘法代替除法</p>
<p>(替代方法不等价，很多编译器都不会(而且不应该)帮你做这种优化)</p>
<p>比如： double x=y/21.3432575;</p>
<p>改成： double x=y*(1/21.3432575); //如果编译器不能优化掉(1/21.3432575),请预先计算出该结果</p>
<p>对于整数，可以使用与定点数相似的方法来处理倒数</p>
<p>(该替代方法不等价)</p>
<p>比如： uint32 x,y; x=y/213;</p>
<p>改成： x=y*((1&lt;&lt;16)/213) &gt;&gt; 16;</p>
<p>某些应用中y*((1&lt;&lt;16)/213)可能会超出值域，这时候可以考虑使用int64来扩大值域</p>
<p>uint32 x=((uint64)y)*((1&lt;&lt;31)/213) &gt;&gt; 31;</p>
<p>也可以使用浮点数来扩大值域</p>
<p>uint32 x=(uint32)(y*(1.0/213)); (警告: 浮点数强制类型转换到整数在很多高级语言里都是</p>
<p>一条很慢的操作，在下几篇文章中将给出其优化的方法)</p>
<p>对于这种方法，某些除法是有与之完全等价的优化方法的：</p>
<p>无符号数除以3： uint32 x,y; x=y/3;</p>
<p>推理: y y y (1&lt;&lt;33)+1 y</p>
<p>x=y/3 =&gt; x=[-] =&gt; x=[- + ---------] =&gt; x=[--------- * -------] // []表示取整</p>
<p>3 3 3*(1&lt;&lt;33) 3 (1&lt;&lt;33)</p>
<p>y 1</p>
<p>(可证明: 0 &lt;= &#8212;&#8212;&#8212; &lt; &#8211; )</p>
<p>3*(1&lt;&lt;33) 3</p>
<p>即： x=(uint64(y)*M)&gt;&gt;33; 其中魔法数M=((1&lt;&lt;33)+1)/3=2863311531=0xAAAAAAAB;</p>
<p>无符号数除以5： uint32 x,y; x=y/5; (y&lt;(1&lt;&lt;31))</p>
<p>推理: y y 3*y (1&lt;&lt;33)+3 y</p>
<p>x=y/5 =&gt; x=[-] =&gt; x=[- + ---------] =&gt; x=[--------- * -------]</p>
<p>5 5 5*(1&lt;&lt;33) 5 (1&lt;&lt;33)</p>
<p>3*y 1</p>
<p>(可证明: 0 &lt;= &#8212;&#8212;&#8212; &lt; &#8211; )</p>
<p>5*(1&lt;&lt;33) 5</p>
<p>即： x=(uint64(y)*M)&gt;&gt;33; 其中魔法数M=((1&lt;&lt;33)+3)/5=1717986919=0&#215;66666667;</p>
<p>无符号数除以7： uint32 x,y; x=y/7;</p>
<p>推理 ：略</p>
<p>即：x=((uint64(y)*M)&gt;&gt;33+y)&gt;&gt;3; 其中魔法数M=((1&lt;&lt;35)+3)/7-(1&lt;&lt;32)=613566757=0&#215;24924925;</p>
<p>对于这种完全等价的替代,还有其他替代公式不再讨论，对于有符号除法的替代算法没有讨论，很多数都有完全等价的替代算法，那些魔法数也是有规律可循的；有“进取心”的编译器应该帮助用户处理掉这个优化(vc6中就已经见到! 偷懒的办法是直接看vc6生成的汇编码:)；</p>
<p>8.对于已知被除数是除数的整数倍数的除法，能够得到替代算法；或改进的算法；</p>
<p>这里只讨论除数是常数的情况；</p>
<p>比如对于(32位除法)：x=y/a; //已知y是a的倍数,并假设a是奇数</p>
<p>(如果a是偶数,先转化为a=a0*(1&lt;&gt;k;a0为奇数)</p>
<p>求得a&#8217;,使 (a&#8217;*a) % (1&lt;&lt;32) = 1；//利用a为奇数,y是a的倍数可以推导出a&#8217;的存在性</p>
<p>那么: x=y/a =&gt; x=(y/a)*((a*a&#8217;) %(1&lt;&lt;32)) =&gt; x=(y*a&#8217;) % (1&lt;&lt;32); //这里并不需要实际做一个求余指令</p>
<p>(该算法可以同时支持有符号和无符号除法)</p>
<p>比如 uint32 y;</p>
<p> uint32 x=y/7; //已知y是7的倍数</p>
<p>改成 uint32 x=(uint32)(y*M); //其中M=(5*(1&lt;&lt;32)+1)/7</p>
<p>9.近似计算除法 (该替代方法不等价)</p>
<p>优化除数255的运算(257也可以,或者1023,1025等等)(1026也可以,推导出的公式略有不同)</p>
<p>比如颜色处理中 ： uint8 color=colorsum/255;</p>
<p>改成： uint8 color=colorsum/256; 也就是 color=colorsum&gt;&gt;8;</p>
<p>这个误差在颜色处理中很多时候都是可以接受的</p>
<p>如果要减小误差可以改成: uint8 color=(colorsum+(colorsum&gt;&gt;8))&gt;&gt;8;</p>
<p>推导: x/255=(x+x/255)/(255+1)=(x+A)&gt;&gt;8; A=x/255;</p>
<p>把A改成A=x&gt;&gt;8 (引入小的误差);带入公式就得到了:x/255约等于(x+(x&gt;&gt;8))&gt;&gt;8的公式</p>
<p>同理可以有x/255约等于(x+(x&gt;&gt;8)+(x&gt;&gt;16))&gt;&gt;8等其它更精确的公式(请推导出误差项已确定是否精度足够)</p>
<p>10. 牛顿迭代法实现除法</p>
<p>(很多CPU的内部除法指令就是用该方法或类似的方法实现的)</p>
<p>假设有一个函数y=f(x); 求0=f(x)时，x的值;(这里不讨论有多个解的情况或逃逸或陷入死循环或陷入混沌状态的问题)</p>
<p><img src="http://p.blog.csdn.net/images/p_blog_csdn_net/housisong/niudun.GIF" border="0" alt="" /></p>
<p>(参考图片)</p>
<p>求函数的导函数为 y=f&#8217;(x); //可以这样来理解这个函数的意思：x点处函数y=f(x)的斜率；</p>
<p>a.取一个合适的x初始值x0; 并得到y0=f(x0);</p>
<p>b.过(x0,y0)作一条斜率为f&#8217;(x0)的直线，与x轴交于x1;</p>
<p>c.然后用得到的x1作为初始值，进行迭代；</p>
<p>当进行足够多次的迭代以后，认为x1将会非常接近于方程0=f(x)的解，这就是牛顿迭代；</p>
<p>把上面的过程化简,得到牛顿迭代公式: x(n+1)=x(n)-y(x(n))/y&#8217;(x(n))</p>
<p>这里给出利用牛顿迭代公式求倒数的方法； (用倒数得到除法: y = x/a = x* (1/a) )</p>
<p>求1/a,</p>
<p>令a=1/x; 有方程 y=a-1/x;</p>
<p>求导得y&#8217;=1/x^2;</p>
<p>代入牛顿迭代方程 x(n+1)=x(n)-y(x(n))/y&#8217;(x(n));</p>
<p>有迭代式 x_next=(2-a*x)*x; //可证明：该公式为2阶收敛公式； 也就是说计算出的解的有效精度成倍增长</p>
<p>证明收敛性:令x=(1/a)+dx; //dx为一个很小的量</p>
<p>则有x_next-(1/a)=(2-a*(1/a+dx))*(1/a+dx)-1/a</p>
<p>=(-a)*dx^2 //^表示指数运算符</p>
<p>证毕.</p>
<p>程序可以用该方法来实现除法，并按照自己的精度要求来决定迭代次数；</p>
<p>(初始值的选取不再讨论)</p>
<p>附录: 用牛顿迭代法来实现开方运算</p>
<p>//开方运算可以表示为 y=x^0.5=1/(1/x^0.5)； 先求1/x^0.5</p>
<p>求1/a^0.5,</p>
<p>令a=1/x^2; 有方程y=a-1/x^2;</p>
<p>求导得y&#8217;=2/x^3;</p>
<p>代入牛顿方程 x(n+1)=x(n)-y(x(n))/y&#8217;(x(n));</p>
<p>有迭代式 x_next=(3-a*x*x)*x*0.5; //可证明：该公式为2阶收敛公式 //方法同上 证明过程略</p>
<p>11. 用快速乘法器实现快速除法</p>
<p>这是存在的一种快速除法算法，当前最好用硬件实现,请查阅相关资料</p>
<p style="text-align: right;">&lt;&lt;代码优化－之－优化除法&gt;&gt; 作者:HouSisong@263.net</p>
<div style="margin-top: 10px">
<p><strong>转载请注明：</strong> 转载自<a href="http://www.xiangmocheng.com/">不然你要我怎么样</a></t>        </br><strong>本文链接地址:</strong> <a href="http://www.xiangmocheng.com/2009/09/code-optimization-division/">【转贴】代码优化－之－优化除法</a></div>
]]></content:encoded>
			<wfw:commentRss>http://www.xiangmocheng.com/2009/09/code-optimization-division/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>【转贴】如何调整Linux内核启动中的驱动初始化顺序</title>
		<link>http://www.xiangmocheng.com/2009/09/how-to-change-linux-booting-sequence/</link>
		<comments>http://www.xiangmocheng.com/2009/09/how-to-change-linux-booting-sequence/#comments</comments>
		<pubDate>Thu, 10 Sep 2009 09:13:32 +0000</pubDate>
		<dc:creator>xiangmocheng</dc:creator>
				<category><![CDATA[Embedded]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[driver]]></category>
		<category><![CDATA[probe]]></category>

		<guid isPermaLink="false">http://xiangmocheng.yo2.cn/articles/%e3%80%90%e8%bd%ac%e8%b4%b4%e3%80%91%e5%a6%82%e4%bd%95%e8%b0%83%e6%95%b4linux%e5%86%85%e6%a0%b8%e5%90%af%e5%8a%a8%e4%b8%ad%e7%9a%84%e9%a9%b1%e5%8a%a8%e5%88%9d%e5%a7%8b%e5%8c%96%e9%a1%ba%e5%ba%8f.html</guid>
		<description><![CDATA[【问题】 此处我要实现的是将芯片的ID用于网卡MAC地址，网卡驱动是enc28j60_init，但是，读取芯片ID的函数，在as352x_afe_init模块中，所以要先初始化as352x_afe_init。此处，内核编译完之后，在生成的system.map中可以看到，enc28j60_init在as352x_afe_init之前，所以，无法去读芯片ID。所以我们的目标是，将as352x_afe_init驱动初始化放到enc28j60_init之前，然后才能读取芯片ID，才能用于网卡初始化的时候的，将芯片ID设置成网卡MAC地址。 【解决过程】 【1】 最简单想到的，是内核里面的 arch\arm\mach-as352x\core.c 中，去改devices设备列表中的顺序。enc28j60_init对应的是ssp_device，因为网卡初始化用到的是SPI驱动去进行和通讯的。as352x_afe_init对应的是afe_device。原先是： 把afe改到最前面： 但是，实际结果是，没有任何影响，连systemp.map生成的，那么模块初始化顺序，都没有任何变化。也就说明，想要实现驱动加载顺序的改变，改core.c里面的设备列表顺序是没有用的。 【2】 在网上看到很多帖子，主要就是这几个： 怎么确定驱动加载顺序 Linux内核驱动程序初始化顺序的调整 内核启动时,设备及驱动初始化的实现 其说明的也很清楚了，就是：Linux内核为不同驱动的加载顺序对应不同的优先级，定义了一些宏：include\linux\init.h 把自己的驱动的函数名用这些宏去定义之后，就会对应不同的加载时候的优先级。 其中，我们写驱动中所用到的module_init对应的是 而 所以，驱动对应的加载的优先级为6。 在上面的不同的优先级中，数字越小，优先级越高。同一等级的优先级的驱动，加载顺序是链接过程决定的，结果是不确定的，我们无法去手动设置谁先谁后。不同等级的驱动加载的顺序是先优先级高，后优先级低，这是可以确定的。所以，像我们之前在驱动中用： 所以，大家都是同一个优先级去初始化，最后这些驱动加载的顺序，可以查看在根目录下，生成的system.map： 。。。 c00197d8 t __initcall_alignment_init5 。。。。。 c00197f4 t __initcall_default_rootfsrootfs c00197f8 t __initcall_timer_init_sysfs6 c00197fc t __initcall_clock_dev_init6 。。。 c00198d8 t __initcall_loop_init6 c00198dc t __initcall_net_olddevs_init6 c00198e0 t __initcall_loopback_init6 c00198e4 t __initcall_enc28j60_init6 。。。 c0019900 t __initcall_as352x_spi_init6 c0019904 t __initcall_spidev_init6 [...]]]></description>
			<content:encoded><![CDATA[<p>【问题】</p>
<p>此处我要实现的是将芯片的ID用于网卡MAC地址，网卡驱动是enc28j60_init，但是，读取芯片ID的函数，在as352x_afe_init模块中，所以要先初始化as352x_afe_init。此处，内核编译完之后，在生成的system.map中可以看到，enc28j60_init在as352x_afe_init之前，所以，无法去读芯片ID。所以我们的目标是，将as352x_afe_init驱动初始化放到enc28j60_init之前，然后才能读取芯片ID，才能用于网卡初始化的时候的，将芯片ID设置成网卡MAC地址。</p>
<p>【解决过程】<span id="more-69431"></span></p>
<p>【1】</p>
<p>最简单想到的，是内核里面的</p>
<p>arch\arm\mach-as352x\core.c</p>
<p>中，去改devices设备列表中的顺序。enc28j60_init对应的是ssp_device，因为网卡初始化用到的是SPI驱动去进行和通讯的。as352x_afe_init对应的是afe_device。原先是：</p>
<pre class="brush: cpp; title: ; notranslate">static struct platform_device *devices[] =
{
	uart_device,
	nand_device,
	afe_device,
	audio_device,
	usb_device,
	as352xkbd_device,
	ssp_device,
};</pre>
<p>把afe改到最前面：</p>
<pre class="brush: cpp; title: ; notranslate">static struct platform_device *devices[] =
{
	afe_device,
	uart_device,
	nand_device,
	audio_device,
	usb_device,
	as352xkbd_device,
	ssp_device,
};</pre>
<p>但是，实际结果是，没有任何影响，连systemp.map生成的，那么模块初始化顺序，都没有任何变化。也就说明，想要实现驱动加载顺序的改变，改core.c里面的设备列表顺序是没有用的。</p>
<p>【2】</p>
<p>在网上看到很多帖子，主要就是这几个：</p>
<p><a href="http://blog.chinaunix.net/u2/72751/showart_1074704.html">怎么确定驱动加载顺序</a><br />
<a href="http://www.itjj.net/tech/OS/Linux/2006-12-21/74501.html">Linux内核驱动程序初始化顺序的调整</a><br />
<a href="http://linux.chinaunix.net/bbs/archiver/tid-1109340.html">内核启动时,设备及驱动初始化的实现</a></p>
<p>其说明的也很清楚了，就是：Linux内核为不同驱动的加载顺序对应不同的优先级，定义了一些宏：include\linux\init.h</p>
<pre class="brush: cpp; title: ; notranslate">#define pure_initcall(fn)        __define_initcall(&quot;0&quot;,fn,0)

#define core_initcall(fn)             __define_initcall(&quot;1&quot;,fn,1)
#define core_initcall_sync(fn)        __define_initcall(&quot;1s&quot;,fn,1s)
#define postcore_initcall(fn)         __define_initcall(&quot;2&quot;,fn,2)
#define postcore_initcall_sync(fn)    __define_initcall(&quot;2s&quot;,fn,2s)
#define arch_initcall(fn)             __define_initcall(&quot;3&quot;,fn,3)
#define arch_initcall_sync(fn)        __define_initcall(&quot;3s&quot;,fn,3s)
#define subsys_initcall(fn)           __define_initcall(&quot;4&quot;,fn,4)
#define subsys_initcall_sync(fn)      __define_initcall(&quot;4s&quot;,fn,4s)
#define fs_initcall(fn)               __define_initcall(&quot;5&quot;,fn,5)
#define fs_initcall_sync(fn)          __define_initcall(&quot;5s&quot;,fn,5s)
#define rootfs_initcall(fn)           __define_initcall(&quot;rootfs&quot;,fn,rootfs)
#define device_initcall(fn)           __define_initcall(&quot;6&quot;,fn,6)
#define device_initcall_sync(fn)      __define_initcall(&quot;6s&quot;,fn,6s)
#define late_initcall(fn)             __define_initcall(&quot;7&quot;,fn,7)
#define late_initcall_sync(fn)        __define_initcall(&quot;7s&quot;,fn,7s)

#define __initcall(fn) device_initcall(fn)</pre>
<p>把自己的驱动的函数名用这些宏去定义之后，就会对应不同的加载时候的优先级。</p>
<p>其中，我们写驱动中所用到的module_init对应的是</p>
<pre class="brush: cpp; title: ; notranslate">#define module_init(x) __initcall(x);</pre>
<p>而</p>
<pre class="brush: cpp; title: ; notranslate">#define __initcall(fn) device_initcall(fn)</pre>
<p>所以，驱动对应的加载的优先级为6。</p>
<p>在上面的不同的优先级中，数字越小，优先级越高。同一等级的优先级的驱动，加载顺序是链接过程决定的，结果是不确定的，我们无法去手动设置谁先谁后。不同等级的驱动加载的顺序是先优先级高，后优先级低，这是可以确定的。所以，像我们之前在驱动中用：</p>
<pre class="brush: cpp; title: ; notranslate">module_init(i2c_dev_init);
module_init(as352x_afe_init);
module_init(as352x_afe_i2c_init);
module_init(enc28j60_init);</pre>
<p>所以，大家都是同一个优先级去初始化，最后这些驱动加载的顺序，可以查看在根目录下，生成的system.map：</p>
<p>。。。<br />
c00197d8 t __initcall_alignment_init5<br />
。。。。。<br />
c00197f4 t __initcall_default_rootfsrootfs<br />
c00197f8 t __initcall_timer_init_sysfs6<br />
c00197fc t __initcall_clock_dev_init6<br />
。。。<br />
c00198d8 t __initcall_loop_init6<br />
c00198dc t __initcall_net_olddevs_init6<br />
c00198e0 t __initcall_loopback_init6<br />
c00198e4 t __initcall_enc28j60_init6<br />
。。。<br />
c0019900 t __initcall_as352x_spi_init6<br />
c0019904 t __initcall_spidev_init6<br />
。。。<br />
c0019920 t __initcall_i2c_dev_init6<br />
c0019924 t __initcall_as352x_afe_i2c_init6<br />
c0019928 t __initcall_as352x_afe_init6<br />
。。。<br />
c0019970 t __initcall_random32_reseed7<br />
c0019974 t __initcall_seqgen_init7<br />
c0019978 t __initcall_rtc_hctosys7<br />
c001997c T __con_initcall_start<br />
c001997c t __initcall_con_init<br />
c001997c T __initcall_end<br />
。。。</p>
<p>此处就是由于<br />
c0019920 t __initcall_i2c_dev_init6<br />
c0019924 t __initcall_as352x_afe_i2c_init6<br />
c0019928 t __initcall_as352x_afe_init6<br />
在<br />
c00198e4 t __initcall_enc28j60_init6<br />
之前，所以我这里才要去改。。。</p>
<p>知道原理，能想到的，就是要么把as352x_afe_init改到enc28j60_init之前一级，即优先级为5。即在驱动中，调用：fs_initcall(as352x_afe_init)；要么把enc28j60_init改到as352x_afe_init之后，即优先级为7。即在驱动中，调用：late_initcall(enc28j60_init)；但是，此处麻烦就麻烦在，如果把as352x_afe_init改到enc28j60_init之前一级，发现后面网卡初始化enc28j60_init中，虽然读取芯片ID对了，但是后面的IP-auto configure 有问题。所以放弃。如果把enc28j60_init改到as352x_afe_init之后，但是，从system.map中看到的是，优先级为7的驱动中，明显有几个驱动，也是和网卡初始化相关的，所以，这样改尝试后，还是失败了。所以，没法简单的通过调整现有的驱动的顺序，去实现顺序的调整。</p>
<p>最后，被逼无奈，想到了一个可以实现我们需求的办法，那就是，单独定义一个优先级，把afe相关的初始化都放到那里面去，这样，就可以保证，其他没什么相关的冲突了。最后证实，这样是可以实现目的的。</p>
<p>具体添加一个新的优先级的步骤如下：</p>
<p>1. 定义新的优先级</p>
<p>include\linux\init.h中：</p>
<pre class="brush: cpp; title: ; notranslate">#define pure_initcall(fn)        __define_initcall(&quot;0&quot;,fn,1)

#define core_initcall(fn)             __define_initcall(&quot;1&quot;,fn,1)
#define core_initcall_sync(fn)        __define_initcall(&quot;1s&quot;,fn,1s)
#define postcore_initcall(fn)         __define_initcall(&quot;2&quot;,fn,2)
#define postcore_initcall_sync(fn)    __define_initcall(&quot;2s&quot;,fn,2s)
#define arch_initcall(fn)             __define_initcall(&quot;3&quot;,fn,3)
#define arch_initcall_sync(fn)        __define_initcall(&quot;3s&quot;,fn,3s)
#define subsys_initcall(fn)           __define_initcall(&quot;4&quot;,fn,4)
#define subsys_initcall_sync(fn)      __define_initcall(&quot;4s&quot;,fn,4s)
#define fs_initcall(fn)               __define_initcall(&quot;5&quot;,fn,5)
#define fs_initcall_sync(fn)          __define_initcall(&quot;5s&quot;,fn,5s)
#define rootfs_initcall(fn)           __define_initcall(&quot;rootfs&quot;,fn,rootfs)
#if 1
#define prev_device_initcall(fn)      __define_initcall(&quot;6&quot;,fn,6)
#define prev_device_initcall_sync(fn) __define_initcall(&quot;6s&quot;,fn,6s)
#define device_initcall(fn)           __define_initcall(&quot;7&quot;,fn,7)
#define device_initcall_sync(fn)      __define_initcall(&quot;7s&quot;,fn,7s)
#define late_initcall(fn)             __define_initcall(&quot;8&quot;,fn,8)
#define late_initcall_sync(fn)        __define_initcall(&quot;8s&quot;,fn,8s)

#else
#define device_initcall(fn)           __define_initcall(&quot;6&quot;,fn,6)
#define device_initcall_sync(fn)      __define_initcall(&quot;6s&quot;,fn,6s)
#define late_initcall(fn)             __define_initcall(&quot;7&quot;,fn,7)
#define late_initcall_sync(fn)        __define_initcall(&quot;7s&quot;,fn,7s)
#endif</pre>
<p>2. 用对应新的宏，定义我们的驱动：prev_device_initcall(i2c_dev_init);prev_device_initcall(as352x_afe_i2c_init);prev_device_initcall(as352x_afe_init);</p>
<p>做到这里，本以为可以了，但是编译后，在system.map中，发现之前优先级为7的那几个函数，被放到system.map最后了，而不是预想的，在优先级7之后，在c001997c T __con_initcall_startc001997c t __initcall_con_initc001997c T __initcall_end之前。</p>
<p>最后，发现时没有把对应的链接文件中的宏加进去：</p>
<p>3. 在include\asm-generic\vmlinux.lds.h中：</p>
<pre class="brush: cpp; title: ; notranslate">#if 1
#define INITCALLS        \
*(.initcall0.init)       \
*(.initcall0s.init)       \
*(.initcall1.init)       \
*(.initcall1s.init)       \
*(.initcall2.init)       \
*(.initcall2s.init)       \
*(.initcall3.init)       \
*(.initcall3s.init)       \
*(.initcall4.init)       \
*(.initcall4s.init)       \
*(.initcall5.init)       \
*(.initcall5s.init)       \
*(.initcallrootfs.init)       \
*(.initcall6.init)       \
*(.initcall6s.init)       \
*(.initcall7.init)       \
*(.initcall7s.init)       \
*(.initcall8.init)       \
*(.initcall8s.init)

#else

#define INITCALLS        \
*(.initcall0.init)       \
*(.initcall0s.init)       \
*(.initcall1.init)       \
*(.initcall1s.init)       \
*(.initcall2.init)       \
*(.initcall2s.init)       \
*(.initcall3.init)       \
*(.initcall3s.init)       \
*(.initcall4.init)       \
*(.initcall4s.init)       \
*(.initcall5.init)       \
*(.initcall5s.init)       \
*(.initcallrootfs.init)       \
*(.initcall6.init)       \
*(.initcall6s.init)       \
*(.initcall7.init)       \
*(.initcall7s.init)

#endif</pre>
<p>最后，再重新编译，就可以实现我们要的，和afe相关的驱动初始化，都在网卡enc28j60_init之前了。也就可以在网卡里面读芯片ID了。当然，对应编译生成的system.map文件中，对应的通过module_init定义的驱动，优先级也都变成7了。而late_initcall对应优先级8了。</p>
<p>【3】不过，最后的最后，竟然发现网卡还是工作不正常，结果第二天，无意间发现是网卡地址设置导致网卡工作不正常的。也就是说，实际是直接将afe设置到原先的优先级5就可以的，而不用这么麻烦去改系统的东西的。。。</p>
<p>不过，至少这也是一种办法，虽然不是那么的好。。。
<div style="margin-top: 10px">
<p><strong>转载请注明：</strong> 转载自<a href="http://www.xiangmocheng.com/">不然你要我怎么样</a></t>        </br><strong>本文链接地址:</strong> <a href="http://www.xiangmocheng.com/2009/09/how-to-change-linux-booting-sequence/">【转贴】如何调整Linux内核启动中的驱动初始化顺序</a></div>
]]></content:encoded>
			<wfw:commentRss>http://www.xiangmocheng.com/2009/09/how-to-change-linux-booting-sequence/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>kmalloc vmalloc malloc区别</title>
		<link>http://www.xiangmocheng.com/2009/09/kmalloc-vmalloc-malloc-difference/</link>
		<comments>http://www.xiangmocheng.com/2009/09/kmalloc-vmalloc-malloc-difference/#comments</comments>
		<pubDate>Wed, 09 Sep 2009 06:23:55 +0000</pubDate>
		<dc:creator>xiangmocheng</dc:creator>
				<category><![CDATA[Embedded]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[kmalloc]]></category>
		<category><![CDATA[malloc]]></category>
		<category><![CDATA[vmalloc]]></category>

		<guid isPermaLink="false">http://xiangmocheng.yo2.cn/articles/kmalloc-vmalloc-malloc%e5%8c%ba%e5%88%ab.html</guid>
		<description><![CDATA[kmalloc()和vmalloc()介绍 kmalloc() 用于申请较小的、连续的物理内存 1. 以字节为单位进行分配，在&#60;linux/slab.h&#62;中 2. void *kmalloc(size_t size, int flags) 分配的内存物理地址上连续，虚拟地址上自然连续 3. gfp_mask标志：什么时候使用哪种标志？如下： &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;- 情形                                                  相应标志 &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;- 进程上下文，可以睡眠                  GFP_KERNEL 进程上下文，不可以睡眠     [...]]]></description>
			<content:encoded><![CDATA[<p><strong>kmalloc()和vmalloc()介绍</strong></p>
<p><span style="color: #ff0000;">kmalloc()</span></p>
<p>用于申请较小的、连续的物理内存</p>
<p>1. 以字节为单位进行分配，在&lt;linux/slab.h&gt;中</p>
<p>2. void *kmalloc(size_t size, int flags) 分配的内存物理地址上连续，虚拟地址上自然连续</p>
<p>3. gfp_mask标志：什么时候使用哪种标志？如下：</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
情形                                                  相应标志<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
进程上下文，可以睡眠                  GFP_KERNEL<br />
进程上下文，不可以睡眠               GFP_ATOMIC<br />
中断处理程序                            GFP_ATOMIC<br />
软中断                                    GFP_ATOMIC<br />
Tasklet                                  GFP_ATOMIC<br />
用于DMA的内存，可以睡眠            GFP_DMA | GFP_KERNEL<br />
用于DMA的内存，不可以睡眠         GFP_DMA | GFP_ATOMIC<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
<p>4. void kfree(const void *ptr)</p>
<p>释放由kmalloc()分配出来的内存块<br />
<span id="more-69429"></span><br />
<span style="color: #ff0000;">vmalloc()</span></p>
<p>用于申请较大的内存空间，虚拟内存是连续的</p>
<p>1. 以字节为单位进行分配，在&lt;linux/vmalloc.h&gt;中</p>
<p>2. void *vmalloc(unsigned long size) 分配的内存虚拟地址上连续，物理地址不连续</p>
<p>3. 一般情况下，只有硬件设备才需要物理地址连续的内存，因为硬件设备往往存在于MMU之外，根本不了解虚拟地址；但为了性能上的考虑，内核中一般使用kmalloc()，而只有在需要获得大块内存时才使用vmalloc()，例如当模块被动态加载到内核当中时，就把模块装载到由vmalloc()分配的内存上。</p>
<p>4.void vfree(void *addr)，这个函数可以睡眠，因此不能从中断上下文调用。</p>
<p><strong>malloc(), vmalloc()和kmalloc()区别</strong></p>
<p>[*]kmalloc和vmalloc是分配的是内核的内存,malloc分配的是用户的内存</p>
<p>[*]kmalloc保证分配的内存在物理上是连续的,vmalloc保证的是在虚拟地址空间上的连续,malloc不保证任何东西(这点是自己猜测的,不一定正确)</p>
<p>[*]kmalloc能分配的大小有限,vmalloc和malloc能分配的大小相对较大</p>
<p>[*]内存只有在要被DMA访问的时候才需要物理上连续</p>
<p>[*]vmalloc比kmalloc要慢
<div style="margin-top: 10px">
<p><strong>转载请注明：</strong> 转载自<a href="http://www.xiangmocheng.com/">不然你要我怎么样</a></t>        </br><strong>本文链接地址:</strong> <a href="http://www.xiangmocheng.com/2009/09/kmalloc-vmalloc-malloc-difference/">kmalloc vmalloc malloc区别</a></div>
]]></content:encoded>
			<wfw:commentRss>http://www.xiangmocheng.com/2009/09/kmalloc-vmalloc-malloc-difference/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>【转贴】Linux kernel 2.6.27内核编译配置选项（一）</title>
		<link>http://www.xiangmocheng.com/2009/06/linux-kernel-2-6-27-configuration-1/</link>
		<comments>http://www.xiangmocheng.com/2009/06/linux-kernel-2-6-27-configuration-1/#comments</comments>
		<pubDate>Tue, 09 Jun 2009 08:42:41 +0000</pubDate>
		<dc:creator>xiangmocheng</dc:creator>
				<category><![CDATA[Embedded]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Kernel]]></category>

		<guid isPermaLink="false">http://xiangmocheng.yo2.cn/articles/%e3%80%90%e8%bd%ac%e8%b4%b4%e3%80%91linux-kernel-2627%e5%86%85%e6%a0%b8%e7%bc%96%e8%af%91%e9%85%8d%e7%bd%ae%e9%80%89%e9%a1%b9%ef%bc%88%e4%b8%80%ef%bc%89.html</guid>
		<description><![CDATA[<p>原文参见<a href="http://www.diybl.com/course/6_system/linux/Linuxjs/2008106/148287.html" target="_blank">这里</a></p>
<p>---------------------------------------------------</p>
<p><span style="font-size: 14px;">General setup<br />常规设置<br /><br /><span style="color: #ff0000;">Prompt for development and/or incomplete code/drivers</span><br />显示尚在开发中或尚未完成的代码与驱动 <br /><span style="color: #ff0000;">Local version - append to kernel release</span><br />在内核版本后面加上自定义的版本字符串(小于64字符),可以用"uname -a"命令看到 <br /><span style="color: #ff0000;">Automatically append version information to the version string</span><br />自动在版本字符串后面添加版本信息,编译时需要有perl以及git仓库支持 <br /><span style="color: #ff0000;">Support for paging of anonymous memory (swap)</span><br />使用交换分区或者交换文件来做为虚拟内存 <br /><span style="color: #ff0000;">System V IPC</span><br />System V进程间通信(IPC)支持,许多程序需要这个功能.必选,除非你知道自己在做什么 <br /><span style="color: #ff0000;">POSIX Message Queues</span><br />POSIX消息队列,这是POSIX IPC中的一部分 <br /><span style="color: #ff0000;">BSD Process Accounting</span><br />将进程的统计信息写入文件的用户级系统调用,主要包括进程的创建时间/创建者/内存占用等信息 <br />&#160;&#160;&#160; <span style="color: #0000ff;">BSD Process Accounting version 3 file format</span><br />&#160;&#160;&#160; 使用新的第三版文件格式,可以包含每个进程的PID和其父进程的PID,但是不兼容老版本的文件格式<br /><span style="color: #ff0000;">Export task/process statistics through netlink</span><br />通过netlink接口向用户空间导出任务/进程的统计信息,与BSD Process Accounting的不同之处在于这些统计信息在整个任务/进程生存期都是可用的（不确定可以不选） <br />&#160;&#160;&#160; <span style="color: #0000ff;">Enable per-task delay accounting</span><br />&#160;&#160;&#160; 在统计信息中包含进程等候系统资源(cpu,IO同步,内存交换等)所花费的时间&#160; <br />&#160;&#160;&#160; <span style="color: #0000ff;">Enable extended accounting over taskstats</span><br />&#160;&#160;&#160; 在统计信息中包含扩展进程所花费的时间&#160; <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; <span style="color: #800080;">Enable per-task storage I/O accounting</span><br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; 在统计信息中包含I/O存储进程所花费的时间 <br /><span style="color: #ff0000;">Auditing support</span><br />审计支持,某些内核模块(例如SELinux)需要它,只有同时选择其子项才能对系统调用进行审计 <br />&#160;&#160;&#160; <span style="color: #0000ff;">Enable system-call auditing support</span><br />&#160;&#160;&#160; 支持对系统调用的审计<br /><span style="color: #ff0000;">Kernel .config support</span><br />把内核的配置信息编译进内核中,以后可以通过scripts/extract-ikconfig脚本来提取这些信息<br />&#160;&#160;&#160; <span style="color: #0000ff;">Enable access to .config through /proc/config.gz</span><br />&#160;&#160;&#160; 允许通过/proc/config.gz访问内核的配置信息 <br /><span style="color: #ff0000;">Kernel log buffer size (16 =&#62; 64KB, 17 =&#62; 128KB)</span><br />内核信息大小<br /><span style="color: #ff0000;">Control Group support</span><br />cgroup支持，如cpusets那样来使用cgroup子系统进程（不确定可以不选） <br />&#160;&#160;&#160; <span style="color: #0000ff;">Example debug cgroup subsystem</span><br />&#160;&#160;&#160; cgroup子系统调试例子&#160; <br />&#160;&#160;&#160; <span style="color: #0000ff;">Namespace cgroup subsystem</span><br />&#160;&#160;&#160; cgroup子系统命名空间&#160; <br />&#160;&#160;&#160; <span style="color: #0000ff;">Device controller for cgroups</span><br />&#160;&#160;&#160; cgroups设备控制器&#160; <br />&#160;&#160;&#160; <span style="color: #0000ff;">Cpuset support</span><br />&#160;&#160;&#160; 只有含有大量CPU(大于16个)的SMP系统或NUMA(非一致内存访问)系统才需要它<br /><span style="color: #ff0000;">Group CPU scheduler</span><br />CPU组调度（Group Scheduling，可以为进程赋予不同于nice level的调度优先级。尤其在企业级硬件系统上，可以进一步优化实时任务的调度。桌面用户可以不选） <br />&#160;&#160;&#160; <span style="color: #0000ff;">Group scheduling for SCHED_OTHER</span><br />&#160;&#160;&#160; SCHED_OTHER（SCHED:Process Scheduler,负责控制进程对CPU的使用.调度算法的公平,有效,硬件有关事件的及时处理）组调度&#160; <br />&#160;&#160;&#160; <span style="color: #0000ff;">Group scheduling for SCHED_RR/FIFO</span><br />&#160;&#160;&#160; SCHED_RR?FIFO组调度&#160; <br />&#160;&#160;&#160; <span style="color: #0000ff;">Basis for grouping tasks</span><br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; 基于分配的任务&#160; <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; <span style="color: #800080;">user id</span><br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; 使用者id&#160; <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; <span style="color: #800080;">Control groups</span><br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; 控制组 <br /><span style="color: #ff0000;">Simple CPU accounting cgroup subsystem</span><br />简单cgroup子系统cpu所花费的时间 <br /><span style="color: #ff0000;">Resource counters</span><br />资源计数器 <br /><span style="color: #ff0000;">Memory Resource Controller for Control Groups</span><br />cgroup内存资源控制器 <br /><span style="color: #ff0000;">Create deprecated sysfs files</span><br />建立过时的sysfs文件系统（虽然写着过时然而许多版本仍然有编译） <br /><span style="color: #ff0000;">Include legacy /proc//cpuset file</span><br />创建/proc//cpuset文件 <br /><span style="color: #ff0000;">Kernel-&#62;user space relay support (formerly relayfs)</span><br />在某些文件系统上(比如debugfs)提供从内核空间向用户空间传递大量数据的接口 <br /><span style="color: #ff0000;">Namespaces support</span><br />命名空间支持，允许服务器为不同的用户信息提供不 同的用户名空间服务 <br />&#160;&#160;&#160; <span style="color: #0000ff;">UTS namespace</span><br />&#160;&#160;&#160; UTS命名空间，不确定可以不选&#160; <br />&#160;&#160;&#160; <span style="color: #0000ff;">IPC namespace</span><br />&#160;&#160;&#160; IPC命名空间，不确定可以不选&#160; <br />&#160;&#160;&#160; <span style="color: #0000ff;">User namespace</span><br />&#160;&#160;&#160; User命名空间，不确定可以不选&#160; <br />&#160;&#160;&#160; <span style="color: #0000ff;">PID Namespaces</span><br />&#160;&#160;&#160; PID命名空间，不确定可以不选<br /><br /><span style="color: #ff0000;">Initial RAM filesystem and RAM disk (initramfs/initrd) support</span><br />初始RAM的文件和RAM磁盘（ initramfs /initrd）支持（如果要采用initrd启动则要选择，否则可以不选） <br />&#160; &#160; <span style="color: #0000ff;">Initramfs source file(s)</span><br />&#160; &#160; initrd已经被initramfs取代,如果你不明白这是什么意思,请保持空白<br /><br /><span style="color: #ff0000;">Optimize for size (Look out for broken compilers!)</span><br />编译时优化内核尺寸(使用"-Os"而不是"-O2"参数编译),有时会产生错误的二进制代码 <br /><span style="color: #ff0000;">Configure standard kernel features (for small systems)</span><br />配置标准的内核特性(为小型系统) <br />&#160;&#160;&#160; <span style="color: #0000ff;">Enable 16-bit UID system calls</span><br />&#160;&#160;&#160; 允许对UID系统调用进行过时的16-bit包装&#160; <br />&#160;&#160;&#160; <span style="color: #0000ff;">Sysctl syscall support</span><br />&#160;&#160;&#160; 不需要重启就能修改内核的某些参数和变量,如果你也选择了支持/proc,将能从/proc/sys存取可以影响内核行为的参数或变量&#160; <br />&#160;&#160;&#160; <span style="color: #0000ff;">Load all symbols for debugging/kksymoops</span><br />&#160;&#160;&#160; 装载
所有的调试符号表信息,仅供调试时选择&#160; <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; <span style="color: #800080;">Include all symbols in kallsyms</span><br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; 在kallsyms中包含内核知道的所有符号,内核将会增大300K&#160; <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; <span style="color: #800080;">Do an extra kallsyms pass</span><br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; 除非你在kallsyms中发现了bug并需要报告这个bug才打开该选项 <br />&#160;&#160;&#160;<span style="color: #0000ff;"> Support for hot-pluggable devices</span><br />&#160;&#160;&#160; 支持热插拔设备,如usb与pc卡等,Udev也需要它&#160; <br />&#160;&#160;&#160; <span style="color: #0000ff;">Enable support for printk</span><br />&#160;&#160;&#160; 允许内核向终端打印字符信息,在需要诊断内核为什么不能运行时选择&#160; <br />&#160;&#160;&#160; <span style="color: #0000ff;">BUG() support</span><br />&#160;&#160;&#160; 显示故障和失败条件(BUG和WARN),禁用它将可能导致隐含的错误被忽略&#160; <br />&#160;&#160;&#160; <span style="color: #0000ff;">Enable ELF core dumps</span><br />&#160;&#160;&#160; 内存转储支持,可以帮助调试ELF格式的程序&#160; <br />&#160;&#160;&#160; <span style="color: #0000ff;">Enable PC-Speaker support</span><br />&#160;&#160;&#160; 允许禁用电脑内部声响<br /><br /><span style="color: #ff0000;">Disable heap randomization</span><br />禁用随机heap（heap堆是一个应用层的概念，即堆对CPU是不可见的，它的实现方式有多种，可以由OS实现，也可以由运行库实现,如果你愿意，你也可以在一个栈中来实现一个堆） <br /><span style="color: #ff0000;">Enable full-sized data structures for core</span><br />在内核中使用全尺寸的数据结构.禁用它将使得某些内核的数据结构减小以节约内存,但是将会降低性能 <br /><span style="color: #ff0000;">Enable futex support</span><br />快速用户空间互斥体可以使线程串行化以避免竞态条件,也提高了响应速度.禁用它将导致内核不能正确的运行基于glibc的程序 <br /><span style="color: #ff0000;">Enable eventpoll support</span><br />支持事件轮循的系统调用 <br /><span style="color: #ff0000;">Enable signalfd() system call</span><br />启用signalfd（）事件的文件描述符系统调用 <br /><span style="color: #ff0000;">Enable timerfd() system call</span><br />启用timerfd（）事件的文件描述符系统调用 <br /><span style="color: #ff0000;">Enable eventfd() system call</span><br />启用eventfd（）事件的文件描述符系统调用 <br /><span style="color: #ff0000;">Use full shmem filesystem</span><br />完全使用shmem来代替ramfs.shmem是基于共享内存的文件系统(可能用到swap),在启用TMPFS后可以挂载为tmpfs供用户空间使用,它比简单的ramfs先进许多 <br /><span style="color: #ff0000;">Enable VM event counters for /proc/vmstat</span><br />允许在/proc/vmstat中包含虚拟内存事件记数器 <br /><span style="color: #ff0000;">Enable SLUB debugging support</span><br />支持SLUB内存分配管理器调试 <br /><span style="color: #ff0000;">Choose SLAB allocator</span><br />选择内存分配管理器（强烈推荐使用SLUB） <br />&#160;&#160;&#160; <span style="color: #0000ff;">SLAB</span><br />&#160;&#160;&#160; 各种环境通用的内存分配管理器&#160; <br />&#160;&#160;&#160; <span style="color: #0000ff;">SLUB (Unqueued Allocator)</span><br />&#160;&#160;&#160; 更加优秀的内存分配管理器&#160; <br />&#160;&#160;&#160; <span style="color: #0000ff;">SLOB (Simple Allocator)</span><br />&#160;&#160;&#160; 嵌入式应用的内存分配管理器<br /><br /><span style="color: #ff0000;">Profiling support</span><br />支持系统评测（对于大多数用户来说并不是必须的） <br /><span style="color: #ff0000;">Activate markers</span><br />激活标志（不确定可以不选） <br /><span style="color: #ff0000;">OProfile system profiling</span><br />OProfile评测和性能监控工具 <br /><span style="color: #ff0000;">Kprobes</span><br />除非开发人员，否则不选 <br /><span style="color: #ff0000;">Enable /proc page monitoring</span><br />启用/proc目录检测<br />&#160;&#160;&#160; <span style="color: #0000ff;">Loadable module support</span><br />&#160;&#160;&#160; 可加载模块支持<br />&#160;&#160;&#160; <span style="color: #0000ff;">Enable loadable module support</span><br />&#160;&#160;&#160; 打开可加载模块支持,如果打开它则必须通过"make modules_install"把内核模块安装在/lib/modules/中 <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; Forced module loading<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; 允许强制加载模块 <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; Module unloading<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; 允许卸载已经加载的模块 <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Forced module unloading<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; 允许强制卸载正在使用中的模块(比较危险)<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; Module versioning support<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; 允许使用其他内核版本的模块(可能会出问题) <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; Source checksum for all modules<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; 为所有的模块校验源码,如果你不是自己编写内核模块就不需要它 <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; Automatic kernel module loading<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; 让内核通过运行modprobe来自动加载所需要的模块,比如可以自动解决模块的依赖关系<br /></span></p>]]></description>
			<content:encoded><![CDATA[<p>原文参见<a href="http://www.diybl.com/course/6_system/linux/Linuxjs/2008106/148287.html" target="_blank">这里</a></p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</p>
<p><span style="font-size: 14px;">General setup<br />
常规设置</span></p>
<p><span style="color: #ff0000;"><span id="more-69401"></span>Prompt for development and/or incomplete code/drivers</span><br />
显示尚在开发中或尚未完成的代码与驱动<br />
<span style="color: #ff0000;">Local version &#8211; append to kernel release</span><br />
在内核版本后面加上自定义的版本字符串(小于64字符),可以用”uname -a”命令看到<br />
<span style="color: #ff0000;">Automatically append version information to the version string</span><br />
自动在版本字符串后面添加版本信息,编译时需要有perl以及git仓库支持<br />
<span style="color: #ff0000;">Support for paging of anonymous memory (swap)</span><br />
使用交换分区或者交换文件来做为虚拟内存<br />
<span style="color: #ff0000;">System V IPC</span><br />
System V进程间通信(IPC)支持,许多程序需要这个功能.必选,除非你知道自己在做什么<br />
<span style="color: #ff0000;">POSIX Message Queues</span><br />
POSIX消息队列,这是POSIX IPC中的一部分<br />
<span style="color: #ff0000;">BSD Process Accounting</span><br />
将进程的统计信息写入文件的用户级系统调用,主要包括进程的创建时间/创建者/内存占用等信息<br />
<span style="color: #0000ff;">BSD Process Accounting version 3 file format</span><br />
使用新的第三版文件格式,可以包含每个进程的PID和其父进程的PID,但是不兼容老版本的文件格式<br />
<span style="color: #ff0000;">Export task/process statistics through netlink</span><br />
通过netlink接口向用户空间导出任务/进程的统计信息,与BSD Process Accounting的不同之处在于这些统计信息在整个任务/进程生存期都是可用的（不确定可以不选）<br />
<span style="color: #0000ff;">Enable per-task delay accounting</span><br />
在统计信息中包含进程等候系统资源(cpu,IO同步,内存交换等)所花费的时间<br />
<span style="color: #0000ff;">Enable extended accounting over taskstats</span><br />
在统计信息中包含扩展进程所花费的时间<br />
<span style="color: #800080;">Enable per-task storage I/O accounting</span><br />
在统计信息中包含I/O存储进程所花费的时间<br />
<span style="color: #ff0000;">Auditing support</span><br />
审计支持,某些内核模块(例如SELinux)需要它,只有同时选择其子项才能对系统调用进行审计<br />
<span style="color: #0000ff;">Enable system-call auditing support</span><br />
支持对系统调用的审计<br />
<span style="color: #ff0000;">Kernel .config support</span><br />
把内核的配置信息编译进内核中,以后可以通过scripts/extract-ikconfig脚本来提取这些信息<br />
<span style="color: #0000ff;">Enable access to .config through /proc/config.gz</span><br />
允许通过/proc/config.gz访问内核的配置信息<br />
<span style="color: #ff0000;">Kernel log buffer size (16 =&gt; 64KB, 17 =&gt; 128KB)</span><br />
内核信息大小<br />
<span style="color: #ff0000;">Control Group support</span><br />
cgroup支持，如cpusets那样来使用cgroup子系统进程（不确定可以不选）<br />
<span style="color: #0000ff;">Example debug cgroup subsystem</span><br />
cgroup子系统调试例子<br />
<span style="color: #0000ff;">Namespace cgroup subsystem</span><br />
cgroup子系统命名空间<br />
<span style="color: #0000ff;">Device controller for cgroups</span><br />
cgroups设备控制器<br />
<span style="color: #0000ff;">Cpuset support</span><br />
只有含有大量CPU(大于16个)的SMP系统或NUMA(非一致内存访问)系统才需要它<br />
<span style="color: #ff0000;">Group CPU scheduler</span><br />
CPU组调度（Group Scheduling，可以为进程赋予不同于nice level的调度优先级。尤其在企业级硬件系统上，可以进一步优化实时任务的调度。桌面用户可以不选）<br />
<span style="color: #0000ff;">Group scheduling for SCHED_OTHER</span><br />
SCHED_OTHER（SCHED:Process Scheduler,负责控制进程对CPU的使用.调度算法的公平,有效,硬件有关事件的及时处理）组调度<br />
<span style="color: #0000ff;">Group scheduling for SCHED_RR/FIFO</span><br />
SCHED_RR?FIFO组调度<br />
<span style="color: #0000ff;">Basis for grouping tasks</span><br />
基于分配的任务<br />
<span style="color: #800080;">user id</span><br />
使用者id<br />
<span style="color: #800080;">Control groups</span><br />
控制组<br />
<span style="color: #ff0000;">Simple CPU accounting cgroup subsystem</span><br />
简单cgroup子系统cpu所花费的时间<br />
<span style="color: #ff0000;">Resource counters</span><br />
资源计数器<br />
<span style="color: #ff0000;">Memory Resource Controller for Control Groups</span><br />
cgroup内存资源控制器<br />
<span style="color: #ff0000;">Create deprecated sysfs files</span><br />
建立过时的sysfs文件系统（虽然写着过时然而许多版本仍然有编译）<br />
<span style="color: #ff0000;">Include legacy /proc//cpuset file</span><br />
创建/proc//cpuset文件<br />
<span style="color: #ff0000;">Kernel-&gt;user space relay support (formerly relayfs)</span><br />
在某些文件系统上(比如debugfs)提供从内核空间向用户空间传递大量数据的接口<br />
<span style="color: #ff0000;">Namespaces support</span><br />
命名空间支持，允许服务器为不同的用户信息提供不 同的用户名空间服务<br />
<span style="color: #0000ff;">UTS namespace</span><br />
UTS命名空间，不确定可以不选<br />
<span style="color: #0000ff;">IPC namespace</span><br />
IPC命名空间，不确定可以不选<br />
<span style="color: #0000ff;">User namespace</span><br />
User命名空间，不确定可以不选<br />
<span style="color: #0000ff;">PID Namespaces</span><br />
PID命名空间，不确定可以不选</p>
<p><span style="color: #ff0000;">Initial RAM filesystem and RAM disk (initramfs/initrd) support</span><br />
初始RAM的文件和RAM磁盘（ initramfs /initrd）支持（如果要采用initrd启动则要选择，否则可以不选）<br />
<span style="color: #0000ff;">Initramfs source file(s)</span><br />
initrd已经被initramfs取代,如果你不明白这是什么意思,请保持空白</p>
<p><span style="color: #ff0000;">Optimize for size (Look out for broken compilers!)</span><br />
编译时优化内核尺寸(使用”-Os”而不是”-O2&#8243;参数编译),有时会产生错误的二进制代码<br />
<span style="color: #ff0000;">Configure standard kernel features (for small systems)</span><br />
配置标准的内核特性(为小型系统)<br />
<span style="color: #0000ff;">Enable 16-bit UID system calls</span><br />
允许对UID系统调用进行过时的16-bit包装<br />
<span style="color: #0000ff;">Sysctl syscall support</span><br />
不需要重启就能修改内核的某些参数和变量,如果你也选择了支持/proc,将能从/proc/sys存取可以影响内核行为的参数或变量<br />
<span style="color: #0000ff;">Load all symbols for debugging/kksymoops</span><br />
装载<br />
所有的调试符号表信息,仅供调试时选择<br />
<span style="color: #800080;">Include all symbols in kallsyms</span><br />
在kallsyms中包含内核知道的所有符号,内核将会增大300K<br />
<span style="color: #800080;">Do an extra kallsyms pass</span><br />
除非你在kallsyms中发现了bug并需要报告这个bug才打开该选项<br />
<span style="color: #0000ff;"> Support for hot-pluggable devices</span><br />
支持热插拔设备,如usb与pc卡等,Udev也需要它<br />
<span style="color: #0000ff;">Enable support for printk</span><br />
允许内核向终端打印字符信息,在需要诊断内核为什么不能运行时选择<br />
<span style="color: #0000ff;">BUG() support</span><br />
显示故障和失败条件(BUG和WARN),禁用它将可能导致隐含的错误被忽略<br />
<span style="color: #0000ff;">Enable ELF core dumps</span><br />
内存转储支持,可以帮助调试ELF格式的程序<br />
<span style="color: #0000ff;">Enable PC-Speaker support</span><br />
允许禁用电脑内部声响</p>
<p><span style="color: #ff0000;">Disable heap randomization</span><br />
禁用随机heap（heap堆是一个应用层的概念，即堆对CPU是不可见的，它的实现方式有多种，可以由OS实现，也可以由运行库实现,如果你愿意，你也可以在一个栈中来实现一个堆）<br />
<span style="color: #ff0000;">Enable full-sized data structures for core</span><br />
在内核中使用全尺寸的数据结构.禁用它将使得某些内核的数据结构减小以节约内存,但是将会降低性能<br />
<span style="color: #ff0000;">Enable futex support</span><br />
快速用户空间互斥体可以使线程串行化以避免竞态条件,也提高了响应速度.禁用它将导致内核不能正确的运行基于glibc的程序<br />
<span style="color: #ff0000;">Enable eventpoll support</span><br />
支持事件轮循的系统调用<br />
<span style="color: #ff0000;">Enable signalfd() system call</span><br />
启用signalfd（）事件的文件描述符系统调用<br />
<span style="color: #ff0000;">Enable timerfd() system call</span><br />
启用timerfd（）事件的文件描述符系统调用<br />
<span style="color: #ff0000;">Enable eventfd() system call</span><br />
启用eventfd（）事件的文件描述符系统调用<br />
<span style="color: #ff0000;">Use full shmem filesystem</span><br />
完全使用shmem来代替ramfs.shmem是基于共享内存的文件系统(可能用到swap),在启用TMPFS后可以挂载为tmpfs供用户空间使用,它比简单的ramfs先进许多<br />
<span style="color: #ff0000;">Enable VM event counters for /proc/vmstat</span><br />
允许在/proc/vmstat中包含虚拟内存事件记数器<br />
<span style="color: #ff0000;">Enable SLUB debugging support</span><br />
支持SLUB内存分配管理器调试<br />
<span style="color: #ff0000;">Choose SLAB allocator</span><br />
<script src="http://www.blogbus.com/user/tiny_mce/themes/advanced/langs/zh.js?4" type="text/javascript"></script><br />
选择内存分配管理器（强烈推荐使用SLUB）<br />
<span style="color: #0000ff;">SLAB</span><br />
各种环境通用的内存分配管理器<br />
<span style="color: #0000ff;">SLUB (Unqueued Allocator)</span><br />
更加优秀的内存分配管理器<br />
<span style="color: #0000ff;">SLOB (Simple Allocator)</span><br />
嵌入式应用的内存分配管理器</p>
<p><span style="color: #ff0000;">Profiling support</span><br />
支持系统评测（对于大多数用户来说并不是必须的）<br />
<span style="color: #ff0000;">Activate markers</span><br />
激活标志（不确定可以不选）<br />
<span style="color: #ff0000;">OProfile system profiling</span><br />
OProfile评测和性能监控工具<br />
<span style="color: #ff0000;">Kprobes</span><br />
除非开发人员，否则不选<br />
<span style="color: #ff0000;">Enable /proc page monitoring</span><br />
启用/proc目录检测<br />
<span style="color: #0000ff;">Loadable module support</span><br />
可加载模块支持<br />
<span style="color: #0000ff;">Enable loadable module support</span><br />
打开可加载模块支持,如果打开它则必须通过”make modules_install”把内核模块安装在/lib/modules/中<br />
Forced module loading<br />
允许强制加载模块<br />
Module unloading<br />
允许卸载已经加载的模块<br />
Forced module unloading<br />
允许强制卸载正在使用中的模块(比较危险)<br />
Module versioning support<br />
允许使用其他内核版本的模块(可能会出问题)<br />
Source checksum for all modules<br />
为所有的模块校验源码,如果你不是自己编写内核模块就不需要它<br />
Automatic kernel module loading<br />
让内核通过运行modprobe来自动加载所需要的模块,比如可以自动解决模块的依赖关系
<div style="margin-top: 10px">
<p><strong>转载请注明：</strong> 转载自<a href="http://www.xiangmocheng.com/">不然你要我怎么样</a></t>        </br><strong>本文链接地址:</strong> <a href="http://www.xiangmocheng.com/2009/06/linux-kernel-2-6-27-configuration-1/">【转贴】Linux kernel 2.6.27内核编译配置选项（一）</a></div>
]]></content:encoded>
			<wfw:commentRss>http://www.xiangmocheng.com/2009/06/linux-kernel-2-6-27-configuration-1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>【转贴】cygwin使用指南</title>
		<link>http://www.xiangmocheng.com/2009/06/cygwin-user-guide/</link>
		<comments>http://www.xiangmocheng.com/2009/06/cygwin-user-guide/#comments</comments>
		<pubDate>Sun, 07 Jun 2009 14:28:40 +0000</pubDate>
		<dc:creator>xiangmocheng</dc:creator>
				<category><![CDATA[Embedded]]></category>
		<category><![CDATA[Cygwin]]></category>

		<guid isPermaLink="false">http://xiangmocheng.yo2.cn/articles/%e3%80%90%e8%bd%ac%e8%b4%b4%e3%80%91cygwin%e4%bd%bf%e7%94%a8%e6%8c%87%e5%8d%97.html</guid>
		<description><![CDATA[作者：yansm cygwin软件下载：这里 1 引言 cygwin是一个在windows平台上运行的unix模拟环境，是cygnus solutions公司开发的自由软件（该公司开发了很多好东西，著名的还有eCos，不过现已被Redhat收购）。它对于学习unix/linux操作环境，或者从unix到windows的应用程序移植，或者进行某些特殊的开发工作，尤其是使用gnu工具集在windows上进行嵌入式系统开发，非常有用。随着嵌入式系统开发在国内日渐流行，越来越多的开发者对cygwin产生了兴趣。本文将对其作一介绍。 2 机理 cygnus当初首先把gcc，gdb，gas等开发工具进行了改进，使他们能够生成并解释win32的目标文件。然后，他们要把这些工具移植到windows平台上去。一种方案是基于win32 api对这些工具的源代码进行大幅修改，这样做显然需要大量工作。因此，他们采取了一种不同的方法——他们写了一个共享库(就是cygwin dll)，把win32 api中没有的unix风格的调用（如fork,spawn,signals,select,sockets等）封装在里面，也就是说，他们基于win32 api写了一个unix系统库的模拟层。这样，只要把这些工具的源代码和这个共享库连接到一起，就可以使用unix主机上的交叉编译器来生成可以在windows平台上运行的工具集。以这些移植到windows平台上的开发工具为基础，cygnus又逐步把其他的工具（几乎不需要对源代码进行修改，只需要修改他们的配置脚本）软件移植到windows上来。这样，在windows平台上运行bash和开发工具、用户工具，感觉好像在unix上工作。 关于cygwin实现的更详细描述，请参考http://cygwin.com/cygwin-ug-net/highlights.html. 3 安装设置cygwin 3.1 安装 要安装网络版的cygwin，可以到http://cygwin.com，点击”Install Cygwin Now!”。这样会先下载一个叫做setup.exe的GUI安装程序，用它能下载一个完整的cygwin。按照每一屏的指示可以方便的进行安装。 3.2 环境变量 开始运行bash之前，应该设置一些环境变量。cygwin提供了一个.bat文件，里面已经设置好了最重要的环境变量。通过它来启动bash是最安全的办法。这个.bat文件安装在cygwin所在的根目录下。 可以随意编辑该文件。 CYGWIN变量用来针对cygwin运行时系统进行多种全局设置。开始时，可以不设置CYGWIN或者在执行bash前用类似下面的格式在dos框下把它设为tty C:\&#62; set CYGWIN=tty notitle glob PATH变量被cygwin应用程序作为搜索可知性文件的路径列表。当一个cygwin进程启动时，该变量被从windows格式(e.g. C:\WinNT\system32;C:\WinNT)转换成unix格式(e.g., /WinNT/system32:/WinNT)。如果想在不运行bash的时候也能够使用cygwin工具集，PATH起码应该包含x:\cygwin\bin，其中x:\cygwin 是你的系统中的cygwin目录。 HOME变量用来指定主目录，推荐在执行bash前定义该变量。当cygwin进程启动时，该变量也被从windows格式转换成unix格式，例如，作者的机器上HOME的值为C:\（dos命令set HOME就可以看到他的值，set HOME=XXX可以进行设置），在bash中用echo $HOME看，其值为/cygdrive/c. TERM变量指定终端型态。如果美对它进行设置，它将自动设为cygwin。 LD_LIBRARY_PATH被cygwin函数dlopen()作为搜索.dll文件的路径列表，该变量也被从windows格式转换成unix格式。多数Cygwin应用程序不使用dlopen,因而不需要该变量。 3.3 改变cygwin的最大存储容量 Cygwin程序缺省可以分配的内存不超过384MB(program+data)。多数情况下不需要修改这个限制。然而，如果需要更多实际或虚拟内存，应该修改注册表的HKEY_LOCAL_MACHINE或HKEY_CURRENT_USER区段。田家一个DWORD键heap_chunk_in_mb并把它的值设为需要的内存限制，单位是十进制MB。也可以用cygwin中的regtool完成该设置。例子如下： regtool -i set /HKLM/Software/Cygnus\ Solutions/Cygwin/heap_chunk_in_mb 1024 regtool -v list /HKLM/Software/Cygnus\ Solutions/Cygwin [...]]]></description>
			<content:encoded><![CDATA[<p>作者：yansm</p>
<p>cygwin软件下载：<a title="cygwin软件下载" href="http://www.cygwin.com/setup.exe">这里</a></p>
<p>1 引言</p>
<p>cygwin是一个在windows平台上运行的unix模拟环境，是cygnus solutions公司开发的自由软件（该公司开发了很多好东西，著名的还有eCos，不过现已被Redhat收购）。它对于学习unix/linux操作环境，或者从unix到windows的应用程序移植，或者进行某些特殊的开发工作，尤其是使用gnu工具集在windows上进行嵌入式系统开发，非常有用。随着嵌入式系统开发在国内日渐流行，越来越多的开发者对cygwin产生了兴趣。本文将对其作一介绍。</p>
<p><span id="more-69397"></span>2 机理</p>
<p>cygnus当初首先把gcc，gdb，gas等开发工具进行了改进，使他们能够生成并解释win32的目标文件。然后，他们要把这些工具移植到windows平台上去。一种方案是基于win32 api对这些工具的源代码进行大幅修改，这样做显然需要大量工作。因此，他们采取了一种不同的方法——他们写了一个共享库(就是cygwin dll)，把win32<br />
api中没有的unix风格的调用（如fork,spawn,signals,select,sockets等）封装在里面，也就是说，他们基于win32 api写了一个unix系统库的模拟层。这样，只要把这些工具的源代码和这个共享库连接到一起，就可以使用unix主机上的交叉编译器来生成可以在windows平台上运行的工具集。以这些移植到windows平台上的开发工具为基础，cygnus又逐步把其他的工具（几乎不需要对源代码进行修改，只需要修改他们的配置脚本）软件移植到windows上来。这样，在windows平台上运行bash和开发工具、用户工具，感觉好像在unix上工作。</p>
<p>关于cygwin实现的更详细描述，请参考http://cygwin.com/cygwin-ug-net/highlights.html.</p>
<p>3 安装设置cygwin</p>
<p>3.1 安装</p>
<p>要安装网络版的cygwin，可以到http://cygwin.com，点击”Install Cygwin Now!”。这样会先下载一个叫做setup.exe的GUI安装程序，用它能下载一个完整的cygwin。按照每一屏的指示可以方便的进行安装。</p>
<p>3.2 环境变量</p>
<p>开始运行bash之前，应该设置一些环境变量。cygwin提供了一个.bat文件，里面已经设置好了最重要的环境变量。通过它来启动bash是最安全的办法。这个.bat文件安装在cygwin所在的根目录下。 可以随意编辑该文件。</p>
<p>CYGWIN变量用来针对cygwin运行时系统进行多种全局设置。开始时，可以不设置CYGWIN或者在执行bash前用类似下面的格式在dos框下把它设为tty</p>
<p>C:\&gt; set CYGWIN=tty notitle glob</p>
<p>PATH变量被cygwin应用程序作为搜索可知性文件的路径列表。当一个cygwin进程启动时，该变量被从windows格式(e.g. C:\WinNT\system32;C:\WinNT)转换成unix格式(e.g., /WinNT/system32:/WinNT)。如果想在不运行bash的时候也能够使用cygwin工具集，PATH起码应该包含x:\cygwin\bin，其中x:\cygwin 是你的系统中的cygwin目录。</p>
<p>HOME变量用来指定主目录，推荐在执行bash前定义该变量。当cygwin进程启动时，该变量也被从windows格式转换成unix格式，例如，作者的机器上HOME的值为C:\（dos命令set HOME就可以看到他的值，set HOME=XXX可以进行设置），在bash中用echo $HOME看，其值为/cygdrive/c.</p>
<p>TERM变量指定终端型态。如果美对它进行设置，它将自动设为cygwin。</p>
<p>LD_LIBRARY_PATH被cygwin函数dlopen()作为搜索.dll文件的路径列表，该变量也被从windows格式转换成unix格式。多数Cygwin应用程序不使用dlopen,因而不需要该变量。</p>
<p>3.3 改变cygwin的最大存储容量</p>
<p>Cygwin程序缺省可以分配的内存不超过384MB(program+data)。多数情况下不需要修改这个限制。然而，如果需要更多实际或虚拟内存，应该修改注册表的HKEY_LOCAL_MACHINE或HKEY_CURRENT_USER区段。田家一个DWORD键heap_chunk_in_mb并把它的值设为需要的内存限制，单位是十进制MB。也可以用cygwin中的regtool完成该设置。例子如下：</p>
<p>regtool -i set /HKLM/Software/Cygnus\ Solutions/Cygwin/heap_chunk_in_mb 1024<br />
regtool -v list /HKLM/Software/Cygnus\ Solutions/Cygwin</p>
<p>4 使用cygwin</p>
<p>这一段讲一下cygwin和传统unix系统的不同之处。</p>
<p>4.1 映射路径名</p>
<p>4.1.1 引言</p>
<p>cygwin<br />
同时支持win32和posix风格的路径，路径分隔符可以是正斜杠也可以是反斜杠。还支持UNC路径名。（在网络中，UNC是一种确定文件位置的方法，使用这种方法用户可以不关心存储设备的物理位置，方便了用户使用。在Windows操作系统，Novell Netware和其它操作系统中，都已经使用了这种规范以取代本地命名系统。在UNC中，我们不用关心文件在什么盘（或卷）上，不用关心这个盘（或卷）所在服务器在什么地方。我们只要以下面格式就可以访问文件：</p>
<p>\\服务器名\共享名\路径\文件名</p>
<p>共享名有时也被称为文件所在卷或存储设备的逻辑标识，但使用它的目的是让用户不必关心这些卷或存储设备所在的物理位置。）</p>
<p>符合posix标准的操作系统（如linux）没有盘符的概念。所有的绝对路径都以一个斜杠开始，而不是盘符（如c:）。所有的文件系统都是其中的子目录。例如，两个硬盘，其中之一为根，另一个可能是在/disk2路径下。</p>
<p>因为许多unix系统上的程序假定存在单一的posix文件系统结构，所以cygwin专门维护了一个针对win32文件系统的内部posix视图，使这些程序可以在windows下正确运行。在某些必要的情况下，cygwin会使用这种映射来进行win32和posix路径之间的转换。</p>
<p>4.1.2 cygwin mount表</p>
<p>cygwin中的mount程序用来把win32盘符和网络共享路径映射到cygwin的内部posix目录树。这是与典型unix mount程序相似的概念。对于那些对unix不熟悉而具有windows背景的的人来说，mount程序和早期的dos命令join非常相似，就是把一个盘符作为其他路径的子目录。</p>
<p>路径映射信息存放在当前用户的cygwin mount表中，这个mount table又在windows的注册表中。这样，当该用户下一次登录进来时，这些信息又从注册表中取出。mount<br />
表分为两种，除了每个用户特定的表，还有系统范围的mount表，每个cygwin用户的安装表都继承自系统表。系统表只能由拥有合适权限的用户（windows nt的管理员）修改。</p>
<p>当前用户的mount表可以在注册表”HKEY_CURRENT_USER/Software/Red Hat, Inc./Cygwin/mounts v” 下看到。系统表存在HKEY_LOCAL_MACHINE下。</p>
<p>posix根路径缺省指向系统分区，但是可以使用mount命令重新指向到windows文件系统中的任何路径。cygwin从win32路径生成posix路径时，总是使用mount表中最长的前缀。例如如果c:被同时安装在/c和/，cygwin将把C:/foo/bar转换成/c/foo/bar.</p>
<p>如果不加任何参数地调用mount命令，会把Cygwin当前安装点集合全部列出。在下面的例子中，c盘是POSIX根，而d盘被映射到/d。本例中，根是一个系统范围的安装点，它对所有用户都是可见的，而/d仅对当前用户可见。</p>
<p>c:\&gt; mount<br />
f:\cygwin\bin on /usr/bin type system (binmode)<br />
f:\cygwin\lib on /usr/lib type system (binmode)<br />
f:\cygwin on / type system (binmode)<br />
e:\src on /usr/src type system (binmode)<br />
c: on /cygdrive/c type user (binmode,noumount)<br />
e: on /cygdrive/e type user (binmode,noumount)</p>
<p>还可以使用mount命令增加新的安装点，用umount删除安装点。</p>
<p>当Cygwin不能根据已有的安装点把某个win32路径转化为posix路径时，cygwin会自动把它转化到一个处于缺省posix路径/cygdrive下的的一个安装点. 例如，如果Cygwin访问Z:\foo，而Z盘当前不在安装表内，那么Z:\将被自动转化成/cygdrive/Z.</p>
<p>可以给每个安装点赋予特殊的属性。自动安装的分区显示为”auto”安装。安装点还可以选择是”textmode”还是”binmode”，这个属性决定了文本文件和二进制文件是否按同样的方式处理。</p>
<p>4.1.3 其他路径相关信息</p>
<p>cygpath工具提供了在shell脚本中进行win32-posix路径格式转换的能力。</p>
<p>HOME, PATH,和LD_LIBRARY_PATH环境变量会在cygwin进程启动时自动被从Win32格式转换成了POSIX格式(例如，如果存在从该win32路径到posix路径的安装，会把c:\cygwin\bin转为/bin。
<div style="margin-top: 10px">
<p><strong>转载请注明：</strong> 转载自<a href="http://www.xiangmocheng.com/">不然你要我怎么样</a></t>        </br><strong>本文链接地址:</strong> <a href="http://www.xiangmocheng.com/2009/06/cygwin-user-guide/">【转贴】cygwin使用指南</a></div>
]]></content:encoded>
			<wfw:commentRss>http://www.xiangmocheng.com/2009/06/cygwin-user-guide/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>【转贴】sizeof(结构体)和内存对齐</title>
		<link>http://www.xiangmocheng.com/2009/03/sizeof-structure-memory-alignment/</link>
		<comments>http://www.xiangmocheng.com/2009/03/sizeof-structure-memory-alignment/#comments</comments>
		<pubDate>Mon, 02 Mar 2009 06:04:00 +0000</pubDate>
		<dc:creator>xiangmocheng</dc:creator>
				<category><![CDATA[Embedded]]></category>
		<category><![CDATA[C]]></category>

		<guid isPermaLink="false">http://xiangmocheng.yo2.cn/articles/%e3%80%90%e8%bd%ac%e8%b4%b4%e3%80%91sizeof%e7%bb%93%e6%9e%84%e4%bd%93%e5%92%8c%e5%86%85%e5%ad%98%e5%af%b9%e9%bd%90.html</guid>
		<description><![CDATA[（一） 有的时候，在脑海中停顿了很久的“显而易见”的东西，其实根本上就是错误的。就拿下面的问题来看： 使用sizeof(T)，将得到什么样的答案呢？要是以前，想都不用想，在32位机中，int是4个字节，char是1个字节，所以T一共是5个字节。实践出真知，在VC6中测试了下，答案确实8个字节。哎，反正受伤的总是我，我已经有点麻木了，还是老老实实的接受吧！为什么答案和自己想象的有出入呢？这里将引入内存对齐这个概念。 许多实际的计算机系统对基本类型数据在内存中存放的位置有限制，它们会要求这些数据的首地址的值是某个数k(通常它为4或8)的倍数，这就是所谓的内存对齐，而这个k则被称为该数据类型的对齐模数(alignment modulus)。当一种类型S的对齐模数与另一种类型T的对齐模数的比值是大于1的整数，我们就称类型S的对齐要求比T强(严格)，而称T比S弱(宽松)。这种强制的要求一来简化了处理器与内存之间传输系统的设计，二来可以提升读取数据的速度。比如这么一种处理器，它每次读写内存的时候都从某个8倍数的地址开始，一次读出或写入8个字节的数据，假如软件能保证double类型的数据都从8倍数地址开始，那么读或写一个double类型数据就只需要一次内存操作。否则，我们就可能需要两次内存操作才能完成这个动作，因为数据或许恰好横跨在两个符合对齐要求的8字节内存块上。某些处理器在数据不满足对齐要求的情况下可能会出错，但是Intel的IA32架构的处理器则不管数据是否对齐都能正确工作。不过Intel奉劝大家，如果想提升性能，那么所有的程序数据都应该尽可能地对齐。 ANSI C标准中并没有规定，相邻声明的变量在内存中一定要相邻。为了程序的高效性，内存对齐问题由编译器自行灵活处理，这样导致相邻的变量之间可能会有一些填充字节。对于基本数据类型(int char)，他们占用的内存空间在一个确定硬件系统下有个确定的值，所以，接下来我们只是考虑结构体成员内存分配情况。 Win32平台下的微软C编译器(cl.exe for 80×86)的对齐策略： 1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除； 备注：编译器在给结构体开辟空间时，首先找到结构体中最宽的基本数据类型，然后寻找内存地址能被该基本数据类型所整除的位置，作为结构体的首地址。将这个最宽的基本数据类型的大小作为上面介绍的对齐模数。 2) 结构体每个成员相对于结构体首地址的偏移量（offset）都是成员大小的整数倍，如有需要编译器会在成员之间加上填充字节（internal adding）； 备注:为结构体的一个成员开辟空间之前，编译器首先检查预开辟空间的首地址相对于结构体首地址的偏移是否是本成员的整数倍，若是，则存放本成员，反之，则在本成员和上一个成员之间填充一定的字节，以达到整数倍的要求，也就是将预开辟空间的首地址后移几个字节。 3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍，如有需要，编译器会在最末一个成员之后加上填充字节（trailing padding）。 备注：结构体总大小是包括填充字节，最后一个成员满足上面两条以外，还必须满足第三条，否则就必须在最后填充几个字节以达到本条要求。 根据以上准则，在windows下，使用VC编译器，sizeof(T)的大小为1(char) + 3(填充) + 4(int) =8个字节。 而在GNU GCC编译器中，遵循的准则有些区别，对齐模数不是像上面所述的那样，根据最宽的基本数据类型来定。在GCC中，对齐模数的准则是：对齐模数最大只能是4，也就是说，即使结构体中有double类型，对齐模数还是4，所以对齐模数只能是1，2，4。而且在上述的三条中，第2条里，offset必须是成员大小的整数倍，如果这个成员大小小于等于4则按照上述准则进行，但是如果大于4了，则结构体每个成员相对于结构体首地址的偏移量（offset）只能按照是4的整数倍来进行判断是否添加填充。 看如下例子： 那么在GCC下，sizeof(T)应该等于12个字节。 如果结构体中含有位域(bit-field)，那么VC中准则又要有所更改： 1) 如果相邻位域字段的类型相同，且其位宽之和小于类型的sizeof大小，则后面的字段将紧邻前一个字段存储，直到不能容纳为止； 2) 如果相邻位域字段的类型相同，但其位宽之和大于类型的sizeof大小，则后面的字段将从新的存储单元开始，其偏移量为其类型大小的整数倍； 3) 如果相邻的位域字段的类型不同，则各编译器的具体实现有差异，VC6采取不压缩方式（不同位域字段存放在不同的位域类型字节中），Dev-C++和GCC都采取压缩方式； 备注：当两字段类型不一样的时候，对于不压缩方式，例如： 依然要满足不含位域结构体内存对齐准则第2条，i成员相对于结构体首地址的偏移应该是4的整数倍，所以c成员后要填充3个字节，然后再开辟4个字节的空间作为int型，其中4位用来存放i，所以上面结构体在VC中所占空间为8个字节；而对于采用压缩方式的编译器来说，遵循不含位域结构体内存对齐准则第2条，不同的是，如果填充的3个字节能容纳后面成员的位，则压缩到填充字节中，不能容纳，则要单独开辟空间，所以上面结构体N在GCC或者Dev-C++中所占空间应该是4个字节。 4) 如果位域字段之间穿插着非位域字段，则不进行压缩； 备注： 结构体 在GCC下占据的空间为16字节，在VC下占据的空间应该是24个字节。 5) 整个结构体的总大小为最宽基本类型成员大小的整数倍。 ps: 对齐模数的选择只能是根据基本数据类型，所以对于结构体中嵌套结构体，只能考虑其拆分的基本数据类型。而对于对齐准则中的第2条，确是要将整个结构体看成是一个成员，成员大小按照该结构体根据对齐准则判断所得的大小。 类对象在内存中存放的方式和结构体类似，这里就不再说明。需要指出的是，类对象的大小只是包括类中非静态成员变量所占的空间，如果有虚函数，那么再另外增加一个指针所占的空间即可。 from：http://www.ksarea.com/articles/20071004_sizeof-struct-memory.html (二) 在ARM 下要使结构体按指定字节对齐，可行的方法有两种： [...]]]></description>
			<content:encoded><![CDATA[<p>（一）</p>
<p>有的时候，在脑海中停顿了很久的“显而易见”的东西，其实根本上就是错误的。就拿下面的问题来看：</p>
<pre class="brush: cpp; title: ; notranslate">

struct T
{
char ch;
int i ;
};</pre>
<p>使用sizeof(T)，将得到什么样的答案呢？要是以前，想都不用想，在32位机中，int是4个字节，char是1个字节，所以T一共是5个字节。实践出真知，在VC6中测试了下，答案确实8个字节。哎，反正受伤的总是我，我已经有点麻木了，还是老老实实的接受吧！为什么答案和自己想象的有出入呢？这里将引入内存对齐这个概念。<span id="more-69362"></span></p>
<p>许多实际的计算机系统对基本类型数据在内存中存放的位置有限制，它们会要求这些数据的首地址的值是某个数k(通常它为4或8)的倍数，这就是所谓的内存对齐，而这个k则被称为该数据类型的对齐模数(alignment modulus)。当一种类型S的对齐模数与另一种类型T的对齐模数的比值是大于1的整数，我们就称类型S的对齐要求比T强(严格)，而称T比S弱(宽松)。这种强制的要求一来简化了处理器与内存之间传输系统的设计，二来可以提升读取数据的速度。比如这么一种处理器，它每次读写内存的时候都从某个8倍数的地址开始，一次读出或写入8个字节的数据，假如软件能保证double类型的数据都从8倍数地址开始，那么读或写一个double类型数据就只需要一次内存操作。否则，我们就可能需要两次内存操作才能完成这个动作，因为数据或许恰好横跨在两个符合对齐要求的8字节内存块上。某些处理器在数据不满足对齐要求的情况下可能会出错，但是Intel的IA32架构的处理器则不管数据是否对齐都能正确工作。不过Intel奉劝大家，如果想提升性能，那么所有的程序数据都应该尽可能地对齐。</p>
<p>ANSI C标准中并没有规定，相邻声明的变量在内存中一定要相邻。为了程序的高效性，内存对齐问题由编译器自行灵活处理，这样导致相邻的变量之间可能会有一些填充字节。对于基本数据类型(int char)，他们占用的内存空间在一个确定硬件系统下有个确定的值，所以，接下来我们只是考虑结构体成员内存分配情况。</p>
<p>Win32平台下的微软C编译器(cl.exe for 80×86)的对齐策略：</p>
<p><span style="color: #ff0000;">1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除；</span></p>
<p><em>备注：编译器在给结构体开辟空间时，首先找到结构体中最宽的基本数据类型，然后寻找内存地址能被该基本数据类型所整除的位置，作为结构体的首地址。将这个最宽的基本数据类型的大小作为上面介绍的对齐模数。</em></p>
<p><span style="color: #ff0000;">2) 结构体每个成员相对于结构体首地址的偏移量（offset）都是成员大小的整数倍，如有需要编译器会在成员之间加上填充字节（internal adding）；</span></p>
<p><em>备注:为结构体的一个成员开辟空间之前，编译器首先检查预开辟空间的首地址相对于结构体首地址的偏移是否是本成员的整数倍，若是，则存放本成员，反之，则在本成员和上一个成员之间填充一定的字节，以达到整数倍的要求，也就是将预开辟空间的首地址后移几个字节。</em></p>
<p><span style="color: #ff0000;">3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍，如有需要，编译器会在最末一个成员之后加上填充字节（trailing padding）。</span></p>
<p><em>备注：结构体总大小是包括填充字节，最后一个成员满足上面两条以外，还必须满足第三条，否则就必须在最后填充几个字节以达到本条要求。<br />
</em><br />
根据以上准则，在windows下，使用VC编译器，sizeof(T)的大小为<span style="color: #ff0000;">1(char) + 3(填充) + 4(int) =8</span>个字节。</p>
<p>而在GNU GCC编译器中，遵循的准则有些区别，对齐模数不是像上面所述的那样，根据最宽的基本数据类型来定。在GCC中，对齐模数的准则是：对齐模数最大只能是4，也就是说，即使结构体中有double类型，对齐模数还是4，所以对齐模数只能是1，2，4。而且在上述的三条中，第2条里，offset必须是成员大小的整数倍，如果这个成员大小小于等于4则按照上述准则进行，但是如果大于4了，则结构体每个成员相对于结构体首地址的偏移量（offset）只能按照是4的整数倍来进行判断是否添加填充。</p>
<p>看如下例子：</p>
<pre class="brush: cpp; title: ; notranslate">struct T
{
char ch;
double d ;
};</pre>
<p>那么在GCC下，sizeof(T)应该等于12个字节。</p>
<p>如果结构体中含有位域(bit-field)，那么VC中准则又要有所更改：</p>
<p>1) 如果相邻位域字段的类型相同，且其位宽之和小于类型的sizeof大小，则后面的字段将紧邻前一个字段存储，直到不能容纳为止；</p>
<p>2) 如果相邻位域字段的类型相同，但其位宽之和大于类型的sizeof大小，则后面的字段将从新的存储单元开始，其偏移量为其类型大小的整数倍；</p>
<p>3) 如果相邻的位域字段的类型不同，则各编译器的具体实现有差异，VC6采取不压缩方式（不同位域字段存放在不同的位域类型字节中），Dev-C++和GCC都采取压缩方式；</p>
<p><em>备注：当两字段类型不一样的时候，对于不压缩方式，例如：</em></p>
<pre class="brush: cpp; title: ; notranslate">struct N
{
char c:2;
int i:4;
};</pre>
<p>依然要满足不含位域结构体内存对齐准则第2条，i成员相对于结构体首地址的偏移应该是4的整数倍，所以c成员后要填充3个字节，然后再开辟4个字节的空间作为int型，其中4位用来存放i，所以上面结构体在VC中所占空间为8个字节；而对于采用压缩方式的编译器来说，遵循不含位域结构体内存对齐准则第2条，不同的是，如果填充的3个字节能容纳后面成员的位，则压缩到填充字节中，不能容纳，则要单独开辟空间，所以上面结构体N在GCC或者Dev-C++中所占空间应该是4个字节。</p>
<p><span style="color: #ff0000;">4) 如果位域字段之间穿插着非位域字段，则不进行压缩；</span></p>
<p><em>备注：</em></p>
<p><em>结构体</em></p>
<pre class="brush: cpp; title: ; notranslate">typedef struct
{
char c:2;
double i;
int c2:4;
}N3;</pre>
<p>在GCC下占据的空间为16字节，在VC下占据的空间应该是24个字节。</p>
<p><span style="color: #ff0000;">5) 整个结构体的总大小为最宽基本类型成员大小的整数倍。</span></p>
<p><strong>ps:</strong></p>
<p>对齐模数的选择只能是根据基本数据类型，所以对于结构体中嵌套结构体，只能考虑其拆分的基本数据类型。而对于对齐准则中的第2条，确是要将整个结构体看成是一个成员，成员大小按照该结构体根据对齐准则判断所得的大小。</p>
<p>类对象在内存中存放的方式和结构体类似，这里就不再说明。需要指出的是，类对象的大小只是包括类中非静态成员变量所占的空间，如果有虚函数，那么再另外增加一个指针所占的空间即可。</p>
<p>from：<a href="http://www.ksarea.com/articles/20071004_sizeof-struct-memory.html">http://www.ksarea.com/articles/20071004_sizeof-struct-memory.html</a></p>
<p>(二)</p>
<p>在ARM 下要使结构体按指定字节对齐，可行的方法有两种：</p>
<p>1.在makefile里增加<span style="color: #ff0000;">-fpack-struct</span>选项，这样的话对所有的结构按一字节对齐。</p>
<p>不得不说，确实有那么些质量较差的程序可能需要你部分自然对齐，部分一字节对齐，此时</p>
<p>2. typedef struct pack{<br />
}__attribute__((packed))</p>
<p>可利用__attribute__属性</p>
<p>当然最后的方式，还是自己去看ARM体系结构与gcc编译选项了。
<div style="margin-top: 10px">
<p><strong>转载请注明：</strong> 转载自<a href="http://www.xiangmocheng.com/">不然你要我怎么样</a></t>        </br><strong>本文链接地址:</strong> <a href="http://www.xiangmocheng.com/2009/03/sizeof-structure-memory-alignment/">【转贴】sizeof(结构体)和内存对齐</a></div>
]]></content:encoded>
			<wfw:commentRss>http://www.xiangmocheng.com/2009/03/sizeof-structure-memory-alignment/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>EE测试题答案</title>
		<link>http://www.xiangmocheng.com/2009/03/ee-test-question-answers/</link>
		<comments>http://www.xiangmocheng.com/2009/03/ee-test-question-answers/#comments</comments>
		<pubDate>Sun, 01 Mar 2009 09:15:00 +0000</pubDate>
		<dc:creator>xiangmocheng</dc:creator>
				<category><![CDATA[Embedded]]></category>

		<guid isPermaLink="false">http://xiangmocheng.yo2.cn/articles/ee%e6%b5%8b%e8%af%95%e9%a2%98%e7%ad%94%e6%a1%88.html</guid>
		<description><![CDATA[<p>终于有人回答了我的问题，真不容易。还是写下答案吧：</p>
<p><img src="http://xiangmocheng.blogbus.com/files/12367465126.jpg" border="0" alt="" /></p>
<p>Q1:图片中是一个（<strong><span style="COLOR: #ff0000">A</span></strong>）<span style="COLOR: #ff0000"><br /></span>A.并行Flash B.串行Flash</p>
<p><span style="COLOR: #0000ff">分析：送分题，会英文就会。</span></p>
<p>Q2:这个东东的Size是（<strong><span style="COLOR: #ff0000">B</span></strong>）</p>
<p>&#160;A.128兆 B.16兆</p>
<p><span style="COLOR: #0000ff">分析：图里标注是&#8220;128Mb&#8221;，所以，不要像我一样以为是128MB，是128M bit = 16MB。</span></p>
<p>Q3:这个东东的数据线是（<strong><span style="COLOR: #ff0000">A</span></strong>）<br />A.8位 B.16位</p>
<p><span style="COLOR: #0000ff">分析：数据线只接了8根，另外8根空着。所以是8位。</span></p>
<p>Q4:这个东东的地址范围是（<strong><span style="COLOR: #ff0000">A</span></strong>）</p>
<p>A.0x000000-0xFFFFFF B.0x000000-0x7FFFFF</p>
<p><span style="COLOR: #0000ff">分析：地址线接了24根，所以最大地址是：0xFFFFFF，结合Q2,Q3可知，flash大小为128*1024*1024 bit，每个数据是8 bit，一除，得到0xFFFFFF。（如果每个数据是16 bit，则地址范围就是0x7FFFFF）</span></p>
<p>Q5:这个东东的sector size是<span style="COLOR: #ff0000"><span style="COLOR: #000000">（</span><span style="COLOR: #ff0000"><strong>B</strong></span></span><span style="COLOR: #000000">）</span></p>
<p><span style="COLOR: #000000">A.64Kbytes B.128Kbytes</span></p>
<p><span style="COLOR: #0000ff">分析：其实只看电路图的接法是不能知道flash的区块大小的。只是图上标了falsh的型号是&#8220;S29GL<span style="COLOR: #ff0000">128</span>N11TF1010&#8221;，所以你可以放心大胆的猜一下是128bytes。。。</span></p>
<p><span style="COLOR: #000000">结论：看来我认识的人里面没有EE。。。</span></p>]]></description>
			<content:encoded><![CDATA[<p>终于有人回答了我的问题，真不容易。还是写下答案吧：</p>
<p><img src="http://xiangmocheng.blogbus.com/files/12367465126.jpg" border="0" alt="" /></p>
<p>Q1:图片中是一个（<strong><span style="COLOR: #ff0000">A</span></strong>）<span style="COLOR: #ff0000"><br /></span>A.并行Flash B.串行Flash</p>
<p><span style="COLOR: #0000ff">分析：送分题，会英文就会。</span></p>
<p>Q2:这个东东的Size是（<strong><span style="COLOR: #ff0000">B</span></strong>）</p>
<p>&nbsp;A.128兆 B.16兆</p>
<p><span style="COLOR: #0000ff">分析：图里标注是&ldquo;128Mb&rdquo;，所以，不要像我一样以为是128MB，是128M bit = 16MB。</span></p>
<p>Q3:这个东东的数据线是（<strong><span style="COLOR: #ff0000">A</span></strong>）<br />A.8位 B.16位</p>
<p><span style="COLOR: #0000ff">分析：数据线只接了8根，另外8根空着。所以是8位。</span></p>
<p>Q4:这个东东的地址范围是（<strong><span style="COLOR: #ff0000">A</span></strong>）</p>
<p>A.0&#215;000000-0xFFFFFF B.0&#215;000000-0x7FFFFF</p>
<p><span style="COLOR: #0000ff">分析：地址线接了24根，所以最大地址是：0xFFFFFF，结合Q2,Q3可知，flash大小为128*1024*1024 bit，每个数据是8 bit，一除，得到0xFFFFFF。（如果每个数据是16 bit，则地址范围就是0x7FFFFF）</span></p>
<p>Q5:这个东东的sector size是<span style="COLOR: #ff0000"><span style="COLOR: #000000">（</span><span style="COLOR: #ff0000"><strong>B</strong></span></span><span style="COLOR: #000000">）</span></p>
<p><span style="COLOR: #000000">A.64Kbytes B.128Kbytes</span></p>
<p><span style="COLOR: #0000ff">分析：其实只看电路图的接法是不能知道flash的区块大小的。只是图上标了falsh的型号是&ldquo;S29GL<span style="COLOR: #ff0000">128</span>N11TF1010&rdquo;，所以你可以放心大胆的猜一下是128bytes。。。</span></p>
<p><span style="COLOR: #000000">结论：看来我认识的人里面没有EE。。。</span></p>
<div style="margin-top: 10px">
<p><strong>转载请注明：</strong> 转载自<a href="http://www.xiangmocheng.com/">不然你要我怎么样</a></t>        </br><strong>本文链接地址:</strong> <a href="http://www.xiangmocheng.com/2009/03/ee-test-question-answers/">EE测试题答案</a></div>
]]></content:encoded>
			<wfw:commentRss>http://www.xiangmocheng.com/2009/03/ee-test-question-answers/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>EE测试题</title>
		<link>http://www.xiangmocheng.com/2009/02/ee-test-questions/</link>
		<comments>http://www.xiangmocheng.com/2009/02/ee-test-questions/#comments</comments>
		<pubDate>Thu, 26 Feb 2009 08:37:00 +0000</pubDate>
		<dc:creator>xiangmocheng</dc:creator>
				<category><![CDATA[Embedded]]></category>

		<guid isPermaLink="false">http://xiangmocheng.yo2.cn/articles/ee%e6%b5%8b%e8%af%95%e9%a2%98.html</guid>
		<description><![CDATA[<p>今天看原理图，惭愧啊惭愧。。。学过的东西都忘得差不多了。。。 <br /><br />所以，请大家来做个小小的的测试！看我是不是应该被鄙视~&#160;<br />&#160;<br /><a href="http://pp.sohu.com/photoview-259411701-14653878.html" target="_blank"></a><img src="http://xiangmocheng.blogbus.com/files/12367465125.jpg" border="0" alt="" /><br /><br />Q1:图片中是一个______ <br />A.并行Flash B.串行Flash <br />&#160;<br />Q2:这个东东的Size是______ <br />A.128兆 B.16兆 <br />&#160;<br />Q3:这个东东的数据线是______ <br />A.8位 B.16位&#160; <br />&#160;<br />Q4:这个东东的地址范围是______ <br />A.0x000000-0xFFFFFF B.0x000000-0x7FFFFF <br />&#160;<br />Q5:这个东东的sector size是______ <br />A.64Kbytes B.128Kbytes</p>]]></description>
			<content:encoded><![CDATA[<p>今天看原理图，惭愧啊惭愧。。。学过的东西都忘得差不多了。。。 </p>
<p>所以，请大家来做个小小的的测试！看我是不是应该被鄙视~&nbsp;<br />&nbsp;<br /><a href="http://pp.sohu.com/photoview-259411701-14653878.html" target="_blank"></a><img src="http://xiangmocheng.blogbus.com/files/12367465125.jpg" border="0" alt="" /></p>
<p>Q1:图片中是一个______ <br />A.并行Flash B.串行Flash <br />&nbsp;<br />Q2:这个东东的Size是______ <br />A.128兆 B.16兆 <br />&nbsp;<br />Q3:这个东东的数据线是______ <br />A.8位 B.16位&nbsp; <br />&nbsp;<br />Q4:这个东东的地址范围是______ <br />A.0&#215;000000-0xFFFFFF B.0&#215;000000-0x7FFFFF <br />&nbsp;<br />Q5:这个东东的sector size是______ <br />A.64Kbytes B.128Kbytes</p>
<div style="margin-top: 10px">
<p><strong>转载请注明：</strong> 转载自<a href="http://www.xiangmocheng.com/">不然你要我怎么样</a></t>        </br><strong>本文链接地址:</strong> <a href="http://www.xiangmocheng.com/2009/02/ee-test-questions/">EE测试题</a></div>
]]></content:encoded>
			<wfw:commentRss>http://www.xiangmocheng.com/2009/02/ee-test-questions/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

