一般的终端模式下,使用的是('/n'), EOF, or EOL 这样一些结束符,可是在某些情况下,我们需要对某些键盘输入做响应,所以,采用的就是非经典模式终端, struct termios { tcflag_t c_iflag; /* 输入模式旗标 */ tcflag_t c_oflag; /* 输出模式旗标 */ tcflag_t c_cflag; /* 控制模式旗标 */ tcflag_t c_lflag; /* 区域模式旗标 */ cc_t c_line; /* 行控制 (line discipline) */ cc_t c_cc[NCCS]; /* 控制特性 */ }; void set_input_mode (void) { struct termios tattr; char *name; /* Make sure stdin is a terminal. */ if (!isatty (STDIN_FILENO)) { fprintf (stderr, "Not a terminal./n"); exit (EXIT_FAILURE); } /* Save the terminal attributes so we can restore them later. */ tcgetattr (STDIN_FILENO, &saved_attributes); atexit (reset_input_mode); /* Set the funny terminal modes. */ tcgetattr (STDIN_FILENO, &tattr); tattr.c_lflag &= ~(ICANON); /* Clear ICANON */ tattr.c_cc[VMIN] = 1; tattr.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &tattr); } |
标签: |
2005-04-19 02:25:20 ![]() |
KERNEL UNDSTAND |
Linux中宏定义很多,而且又分散在各个头文件中,你可以预处理一下,比如 gcc -D__KERNEL__ -E console.c > console.i 这样,console.c中的很多结构定义就在console.i中清晰的暴露了出来;有时可以用nm命令检查一下目标模块的包含的符号名,比如 nm console.o,这样可得知console.o引用了那些外部符号,它自已定义了哪些符号; 另 一个方法是剖析运行中的系统.编绎内核产生的System.map文件非常重要,它包含了内核地址空间中各种符号名的地址,你可以用 System.map,结合源码,通过/dev/kmem检查内核中的各种数据结构,你也可以通过/dev/mem用物理地址来检查内存数据 |
标签: |
2005-04-19 02:12:41 ![]() |
rh9 2.4.20下模块printk 找不到连接 |
编译都没有了问题。 在加载模块时,出现了说printk这个符号无法解释的问题, 与一般模式下相同,一定是这个printk找不到实现, 原来是在kenel中有一个export table包含了所有kernel中 可以使用的function,ksyms -a 得到 c0216ba0 drive_info_R744aa133 c01e4a44 boot_cpu_data_R660bd466 c01e4ac0 EISA_bus_R7413793a c01e4ac4 MCA_bus_Rf48a2c4c c010cc34 __verify_write_R203afbeb 。。。 入口对应的就是函数名,可是这个函数名太诡异了啊,其实这是一个 版本号,来保证内核的稳定开发的,所以我们在使用printk时 需要指定这个版本号, 解决的办法: 要嘛就是将 kernel 里的 set version 选项关掉, #ifdef MODVERSIONS #include <linux/modversions.h> #endif 要嘛就是将 module compile 成 kernel 有办法接受的型式。这个办法可以使用宏替换 不过何必呢。呵呵 #ifndef __KERNEL__ #define __KERNEL__ #endif #include </usr/src/linux-2.4.20-8/include/linux/version.h> #ifndef MODULE #define MODULE #endif #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #ifdef MODVERSIONS #include <linux/modversions.h> #endif static int __init init(void) { printk("<0>init/n"); return 0; } static void __exit fini(void) { printk("<0>exit/n"); } module_init(init); module_exit(fini); MODULE_LICENSE("GPL"); /* module.c */ INCLUDEDIR = /usr/src/linux-2.4.20-8/include CC = gcc LD = ld CFLAGS = -D__KERNEL__ -DMODULE -DMODVERSIONS -O -Wall -Wstrict-prototypes -I$(INCLUDEDIR) VER = 2.4.20-8 OBJS = hello.o all:$(OBJS) hello.o:hello.c $(CC) $(CFLAGS) -c $^ -o $@ clean: rm -f *.o rm -f core |
标签: |
2005-04-16 02:06:56 ![]() |
iptables下udp穿越基础篇----iptables与stun [zz] |
Stun协议(Rfc3489、详见 ![]() A机器在私网(192.168.0.4) NAT服务器(210.21.12.140) B机器在公网(210.15.27.166) C机器在公网(210.15.27.140) 现在,A机器连接过B机器,假设是 A(192.168.0.4:5000)-> NAT(转换后210.21.12.140:8000)-> B(210.15.27.166:2000)。 同时A从来没有和C通信过。 则对于不同类型的NAT,有下列不同的结果: Full Cone NAT:C发数据到210.21.12.140:8000,NAT会将数据包送到A(192.168.0.4:5000)。因为NAT上已经有了192.168.0.4:5000到210.21.12.140:8000的映射。 Restricted Cone: C无法和A通信,因为A从来没有和C通信过,NAT将拒绝C试图与A连接的动作。但B可以通过210.21.12.140:8000与A的 192.168.0.4:5000通信,且这里B可以使用任何端口与A通信。如:210.15.27.166:2001 -> 210.21.12.140:8000,NAT会送到A的5000端口上。 Port Restricted Cone:C无法与A通信,因为A从来没有和C通信过。而B也只能用它的210.15.27.166:2000与A的192.168.0.4:5000通信,因为A也从来没有和B的其他端口通信过。该类型NAT是端口受限的。 Symmetric NAT: 上面3种类型,统称为Cone NAT,有一个共同点:只要是从同一个内部地址和端口出来的包,NAT都将它转换成同一个外部地址和端口。但是 Symmetric有点不同,具体表现在:只要是从同一个内部地址和端口出来,且到同一个外部目标地址和端口,则NAT也都将它转换成同一个外部地址和端 口。但如果从同一个内部地址和端口出来,是到另一个外部目标地址和端口,则NAT将使用不同的映射,转换成不同的端口(外部地址只有一个,故不变)。而且 和Port Restricted Cone一样,只有曾经收到过内部地址发来包的外部地址,才能通过NAT映射后的地址向该内部地址发包。 现针对Symmetric NAT举例说明(例2): A机器连接过B机器,假使是 A(192.168.0.4:5000)-> NAT(转换后210.21.12.140:8000)-> B(210.15.27.166:2000) 如 果此时A机器(192.168.0.4:5000)还想连接C机器(210.15.27.140:2000),则NAT上产生一个新的映射,对应的转换可 能为A(192.168.0.4:5000)-> NAT(转换后210.21.12.140:8001)-> C (210.15.27.140:2000)。此时,B只能用它的210.15.27.166:2000通过NAT的210.21.12.140:8000 与A的192.168.0.4:5000通信, C也只能用它的210.15.27.140:2000通过NAT的210.21.12.140:8001 与A的192.168.0.4:5000通信,而B或者C的其他端口则均不能和A的192.168.0.4:5000通信。 通过上面的例子,我们清楚了Stun协议对NAT进行分类的依据。那么,我们现在根据上述分类标准(或例子),来简要分析一下iptables的工作原理(仅指MASQUERADE、下同),看看他又是属于哪种NAT呢? 首先,我们去网上下载一个使用Stun协议检测NAT的工具,网址在 ![]() 我们先不要急着接受这个检测结果,还是先来分析一下iptables的工作原理吧! iptables在转换地址时,遵循如下两个原则: 1、尽量不去修改源端口,也就是说,ip伪装后的源端口尽可能保持不变。(即所谓的Preserves port number) 2、更为重要的是,ip伪装后只需保证伪装后的源地址/端口与目标地址/端口(即所谓的socket)唯一即可。 仍以前例说明如下(例3): A机器连接过B机器,假使是 A(192.168.0.4:5000)-> NAT(转换后210.21.12.140:5000)-> B(210.15.27.166:2000)。(注意,此处NAT遵循原则1、故转换后端口没有改变) 如 果此时A机器(192.168.0.4:5000)还想连接C机器(210.15.27.140:2000),则NAT上产生一个新的映射,但对应的转换 仍然有可能为A(192.168.0.4:5000)-> NAT(转换后210.21.12.140:5000)-> C (210.15.27.140:2000)。这是因为NAT(转换后210.21.12.140:5000)-> B (210.15.27.166:2000)和NAT(转换后210.21.12.140:5000)-> C(210.15.27.140: 2000)这两个socket不重复。因此,对于iptables来说,这既是允许的(第2条原则)、也是必然的(第1条原则)。 在该例中,表 面上看起来iptables似乎不属于Symmetric NAT,因为它看起来不符合Symmetric NAT的要求:如果从同一个内部地址和端口出 来,是到另一个目标地址和端口,则NAT将使用不同的映射,转换成不同的端口(外部地址只有一个,故不变)。相反,倒是符合除Symmetric NAT 外的三种Cone NAT的要求:从同一个内部地址和端口出来的包,NAT都将它转换成同一个外部地址和端口。加上iptables具有端口受限的属性 (这一点不容置疑,后面举反例证明之),所以好多检测工具就把iptables报告为Port restricted NAT类型了。 下面仍以前例接着分析(例4): 在前例中增加D机器在A同一私网(192.168.0.5) A机器连接过B机器,假使是 A(192.168.0.4:5000)-> NAT(转换后210.21.12.140:5000)-> B(210.15.27.166:2000) D机器连接过C机器,假使是 D(192.168.0.5:5000)-> NAT(转换后210.21.12.140:5000)-> C(210.15.27.140:2000) 由iptables转换原则可知,上述两个转换是允许且必然的。 如 果此时A机器(192.168.0.4:5000)还想连接C机器(210.15.27.140:2000),则NAT上产生一个新的映射,但对应的转换 则变为A(192.168.0.4:5000)-> NAT(转换后210.21.12.140:5001)-> C (210.15.27.140:2000)。这是因为,如果仍然将其转换为210.21.12.140:5000的话,则其所构成的socket (210.21.12.140:5000->210.15.27.140:2000)将和D->C的socket一致,产生冲突,不符合 iptables的第2条原则(注意,此处以5001表示转换后不同的端口,但事实上,iptables却并不按照内部端口+1的原则来产生新的端口)。 在本例中我们注意到,从同一个内部地址和端口A(192.168.0.4:5000)出来,到不同的目标地址和端口,则NAT使用了不同的映射,转换成不 同的端口。 上面这个例子在实际环境中比较少见,我们再以QQ为例举一个真实且常见的例子(例5)。 假设 A(192.168.0.4)和 D(192.168.0.5)是同一NAT服务器(210.21.12.140)保护的两台私网机器,都运行了QQ客户端程序。 B机器在公网(210.15.27.166),运行QQ服务器程序。 C机器在公网(210.15.27.140),运行QQ客户端程序。 A上QQ先登陆到B,按照原则1,使用如下映射: A(192.168.0.4:4000)-> NAT(转换后210.21.12.140:4000)-> B(210.15.27.166:8000)(原则1,端口不变) 接着D上QQ也登陆到B,按照原则2,使用如下映射: D(192.168.0.5:4000)-> NAT(转换后210.21.12.140:4001)-> B(210.15.27.166:8000)(原则2,scoket不能有重复,此处4001仅表示转换后不同的端口,实际环境中决不是4001) 然后D欲和公网C(210.15.27.140)上的QQ通信,按照iptables转换原则,使用如下映射: D(192.168.0.5:4000)-> NAT(转换后210.21.12.140:4000)-> C(210.15.27.140:4000) 到此我们发现,和上例一样,从同一个内部地址和端口D(192.168.0.5:4000)出来,到不同的目标地址和端口,则NAT使用了不同的映射,转换成不同的端口。但和上例不一样的是,本例显然普遍存在于实际环境中。 上面所举两例表明,结论刚好和例3相反,即iptables应该属于Symmetric NAT。 为 什么会出现彼此矛盾的情况呢?首先从NAT分类的定义上来看, Stun协议和iptables对映射的理解不同。Stun协议认为,一个映射的要素是: 内部地址端口和NAT转换后地址端口的组合。而在iptables看来,一个映射的要素是:NAT转换后地址端口和外部目标地址端口的组合。另一方面则是 Stun协议里Discovery Process给出的测试环境不够全面之故,他只考虑了NAT后面仅有一台私网机器的特例(例3),没有考虑NAT后 面可以有多台私网机器的普遍例子(例5)。正是由于这两个原因,直接导致了上述矛盾的发生。所以,凡按照Stun协议标准设计的NAT分类检测工具对 iptables的检测结果必然是Port restricted NAT。(事实上,在例3那样的特例下,iptables确实是一个标准的 Port restricted NAT) 那么,iptables究竟属于哪种NAT呢?我们再来回顾一下Stun协议对Cone NAT的要 求:所有(或只要是)从同一个内部地址和端口出来的包,NAT都将它转换成同一个外部地址和端口。虽然iptables在部分情况下满足“从同一个内部地 址和端口出来的包,都将把他转换成同一个外部地址和端口”这一要求,但它不能在所有情况下满足这一要求。所以理论上,我们就只能把iptables归为 Symmetric NAT了。 下面,我们再来分析一下iptables的端口受限的属性,我们举一个反例证明之(例6),仍以前例说明如下: A机器连接过B机器,假使是 A(192.168.0.4:5000)-> NAT(转换后210.21.12.140:5000)-> B(210.15.27.166:2000) D机器连接过C机器,假使是 D(192.168.0.5:5000)-> NAT(转换后210.21.12.140:5000)-> C(210.15.27.140:2000) 现 假设iptables不具有端口受限的属性,则另一E机器在公网(210.15.27.153:2000)或C(210.15.27.140:2001) 向210.21.12.140:5000发包的话,应该能够发到内部机器上。但事实是,当这个包到达NAT(210.21.12.140:5000)时, NAT将不知道把这个包发给A(192.168.0.4:5000)还是D(192.168.0.5:5000)。显然,该包只能丢弃,至此,足以证明 iptables具有端口受限的属性。 所以,iptables是货真价实的Symmetric NAT。 附: 1、Stun全称Simple Traversal of UDP Through NATs,所以本文所涉及的包,皆为UDP包。 2、 本文虽然是针对linux下iptables的分析,但倘若把本文中关键词“iptables”换成“Win2000下的ics或nat”,则本文的分析 过程完全适用于Win2000下的ics或nat。即理论上Win2000下的ics或nat也是货真价实的Symmetric NAT,但实际上,凡按 照Stun协议标准设计的NAT分类检测工具对其检测结果也必然是Port restricted NAT。其实,不光是linux下iptables、 或者Win2000下的ics或nat、再或者任何其他NAT产品,只要他们遵循和iptables一样的两条转换原则,那么他们在Stun协议下的表现 是完全一样的。 3、虽然Win2000下的ics或nat在Stun协议下的表现和iptables完全一样,但其NAT时所遵循的原则1和 iptables还是略有差别:iptables对内部私网机器来的所有源端口都将适用Preserves port number,除非确因原则2发生 冲突而不得不更换源端口号,但在更换端口号时并不遵循内部端口+1原则(似乎没有规律)。Win2000下的ics或nat则仅对内部私网机器来的部分源 端口(1025--3000)适用Preserves port number,对于那些超过3000的源端口号或者因原则2发生冲突的端口号,系统从 1025开始重新按序分配端口,在此过程中,仍然遵循如前两个原则,只是原则1不再Preserves port number而已(在不与原则2发生冲 突的前提下,尽量重复使用小的端口号,故使用1025的几率远远大于1026、1027…)。 即将推出其姊妹篇----iptables下udp穿越实用篇----“iptables与natcheck” ![]() |
标签: |
2005-04-15 01:35:38 ![]() |
一个诡异的C调用 |
实现的是一个空调用实现一个函数调用,这话说得就很奇怪吧。^_^ 看程序 void f() { printf("this is a call"); } int main() { int buf[1]; buf[2] = (int)f; return 0; }j 这个函数没有一个地方是调用f的,注意这一点哦 这是因为buf[2]的溢出覆盖了main的返回地址 高 -- 》 低 [eip] [ebp] [buf[0]] f函数f的地址 被放到了 ebp+8的地方,也就是刚好是[eip]的位置。 ![]() ebp+8是怎么产生出来的呢?嘿嘿。对于栈的访问c的策略就是ebp+位置,ebp-8放的是buf[0]的值 ebp 是buf[1]嘿嘿。知道了吧 可以 cl /FA 来产生汇编码细细的看这个。 mov DWORD PTR _buff$[ebp+8], OFFSET FLAT:_f |
标签: |
2005-04-15 01:04:56 ![]() |
经典CC++面试题(han) |
链表与数组的区别 A 从逻辑结构来看 A-1. 数组必须事先定义固定的长度(元素个数),不能适应数据动态地增减的情况。当 数据增加时,可能超出原先定义的元素个数;当数据减少时,造成内存浪费。 A-2. 链表动态地进行存储分配,可以适应数据动态地增减的情况,且可以方便地插入、 删除数据项。(数组中插入、删除数据项时,需要移动其它数据项) B 从内存存储来看 B-1. (静态)数组从栈中分配空间, 对于程序员方便快速,但是自由度小 B-2. 链表从堆中分配空间, 自由度大但是申请管理比较麻烦. 堆和栈的区别 solost 于 2004年 10月09日 发表 一、预备知识—程序的内存分配 一个由c/C++编译的程序占用的内存分为以下几个部分 1、栈区(stack)— 由编译器(Compiler)自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。 2、堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。 3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 - 程序结束后有系统释放 4、文字常量区 — 常量字符串就是放在这里的。 程序结束后由系统释放 5、程序代码区— 存放函数体的二进制代码。 二、例子程序 这是一个前辈写的,非常详细 //main.cpp int a = 0; 全局初始化区 char *p1; 全局未初始化区 main() { int b; 栈 char s[] = "abc"; 栈 char *p2; 栈 char *p3 = "123456"; 123456/0在常量区,p3在栈上。 static int c =0; 全局(静态)初始化区 p1 = (char *)malloc(10); p2 = (char *)malloc(20); 分配得来得10和20字节的区域就在堆区。 strcpy(p1, "123456"); 123456/0放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。 } 二、堆和栈的理论知识 2.1申请方式 stack: 由系统自动分配。 例如,声明在函数中一个局部变量 int b; 系统自动在栈中为b开辟空间 heap: 需要程序员自己申请,并指明大小,在c中malloc函数 如p1 = (char *)malloc(10); 在C++中用new运算符 如p2 = (char *)malloc(10); 但是注意p1、p2本身是在栈中的。 2.2 申请后系统的响应 栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。 堆:首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时, 会 遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内 存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大 小,系统会自动的将多余的那部分重新放入空闲链表中。 2.3申请大小的限制 栈:在Windows下, 栈是向低地址扩展的数 据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在WINDOWS下,栈的大小是2M(也有的说是1M,总 之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。 堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。 2.4申请效率的比较: 栈由系统自动分配,速度较快。但程序员是无法控制的。 堆是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便. 另外,在WINDOWS下,最好的方式是用VirtualAlloc分配内存,他不是在堆,也不是在栈是直接在进程的地址空间中保留一快内存,虽然用起来最不方便。但是速度快,也最灵活。 2.5堆和栈中的存储内容 栈: 在函数调用时,(1) 第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的地址,(2) 然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,(3) 然后是函数中的局部变量。 注意: 静态变量是不入栈的。 当本次函数调用结束后,(1) 局部变量先出栈,(2) 然后是参数,(3) 最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。 堆:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容有程序员安排。 2.6存取效率的比较 char s1[] = "aaaaaaaaaaaaaaa"; char *s2 = "bbbbbbbbbbbbbbbbb"; aaaaaaaaaaa是在运行时刻赋值的; 而bbbbbbbbbbb是在编译时就确定的; 但是,在以后的存取中,在栈上的数组比指针所指向的字符串(例如堆)快。 比如: #include void main() { char a = 1; char c[] = "1234567890"; char *p ="1234567890"; a = c[1]; a = p[1]; return; } 对应的汇编代码 10: a = c[1]; 00401067 8A 4D F1 mov cl,byte ptr [ebp-0Fh] 0040106A 88 4D FC mov byte ptr [ebp-4],cl 11: a = p[1]; 0040106D 8B 55 EC mov edx,dword ptr [ebp-14h] 00401070 8A 42 01 mov al,byte ptr [edx+1] 00401073 88 45 FC mov byte ptr [ebp-4],al 第一种在读取时直接就把字符串中的元素读到寄存器cl中,而第二种则要先把指针值读到edx中,在根据edx读取字符,显然慢了。 2.7小结: 堆和栈的区别可以用如下的比喻来看出: 使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。 使用堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。 深度优先搜索与广度优先搜索算法有何区别呢? 通常深度优先搜索法不全部保留结点,扩展完的结点从数据库中弹出删去,这样,一般在数据库中存储的结点数就是深度值,因此它占用空间较少。所以,当搜索树的结点较多,用其它方法易产生内存溢出时,深度优先搜索不失为一种有效的求解方法。 广度优先搜索算法,一般需存储产生的所有结点,占用的存储空间要比深度优先搜索大得多,因此,程序设计中,必须考虑溢出和节省内存空间的问题。但广度优先搜索法一般无回溯操作,即入栈和出栈的操作,所以运行速度比深度优先搜索要快些 |
标签: |
2005-04-13 01:17:48 ![]() |
inside Win2k (1) |
inside win2k中,提到IRQL高于DPC级别的就无法使用页式内存,因为要是出现缺页不在物理内存的情况需要 调用磁盘IO换页,这样的响应时间就无法保证了,这是很好理解的。可是问题是:无法使用页式内存就要求 是使用物理内存,这样的话,要是这些物理内存是没有数据的还讲的通,页表在对这些页面访问时就都无法 访问。可是要是物理内存是分配出去的,被某些页表使用,那数据需要换出,这样不也就违背了不使用页式 内存的初衷?页式内存VS物理内存!GDTL.全局页表。LDT。局部页表。 还有,DPC的设置,感觉是比较好的防止优先权倒置的好的办法,把中断处理的任务尽可能的拖到DPC去实现 就保证IRQL不是老是处于高级别,这样有中断发生时,OS可以快速的响应。D可是,理解来说还是没有问题 现在的问题是,要是驱动的中断响应结束了,这余下的任务拖到DPC去在有时间的时候实现,这样如何保证 同步性,因为下次中断又接着马上就到了了,要是它依赖与上次事件的话,这样可怎么不?我想应该 没有问题,可是详细的理解又有问题。 OS高得头都大了。唉。 |
标签: |
2005-04-13 00:02:15 ![]() |
2.6内核模块编译的变化 |
![]() 2。4的不行了老的编译 #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> static int dummy_init(void) { printk("hello,world./n"); return 0; } static void dummy_exit(void) { return; } module_init(dummy_init); module_exit(dummy_exit); MODULE_LICENSE("GPL") ------------------------------8 cut here 8----------------------------------- # gcc -c -O2 -DMODULE -D__KERNEL__ -I/usr/src/linux test.c # insmod test.o No module found in object insmod: error inserting 'test.o': -1 Invalid module format 准确的做法是: 正确的做法是写一个Makefile,由内核的Kbuild来帮你编译 -------------------------------8 Makefile 8----------------------------------- obj-m := module.o KDIR := /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) default: $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules --------------------------------8 cut here 8---------------------------------- |
标签: |
2005-04-10 01:33:15 ![]() |
M$太e了 |
现在觉得被人逼着换技术的郁闷了。居然不再使用VC6。我考 You cannot - I received word from the SDK team that VC++ 6.0 is no longer a supported product. The last version to support VC++ 6.0 is the February 2003 SDK. No further Platform SDKs will be released that support VC++ 6.0. This includes the upcoming release of the Windows 2003 Server SP1 SDK. Please make your views known to Microsoft whether you agree with this decision. One workaround is to copy only the lib files you are having problems with (e.g. uuid.lib, shell32.lib, msxml2.lib, and possibly others) from the Feb 2003 version. This also means that if they add any new functions to those libs you will be missing out. 分析原因呢? M$ SDK组说是BUG,编译器产生了叫连接器无法识别的符合。按照MSDN给出 的解决方法,关优化,Enable Function-Level Linking 都不行 我觉得是m$把库给更新了 新的库中使用了新的符合定义,只有V7的连接才认。我FT. |
标签: |
2005-04-05 21:34:39 ![]() |
vmvare&bochs |
vmvare是有linux/win下两个版本,有点吃内存,不过还是很爽的,装了redhat9. 注意:要实现shared doc, 首先要选好共享的文件夹 就需要在启动redhat后,安装工具。然后 su /sbin/telinit 3进入文字界面。 mount /dev/cdrom /mnt/cdrom cp vmvare_tools.tar.gz /tmp tar zxf vmvare_tools.tar.gz ./install.pl 然后再 telinit 5进入图形界面 /mnt/fsgh下的就是一个共享文件夹了 就不需要什么网络了,不过注意的是,要是安装网络的话,主要要把网卡 高级选项选为可为其它网络共享。 ![]() bochs bochs.sourceforge.net Bochs is a program that simulates a complete Intel x86 computer Bochs is written in the C++ programming language, and is designed to run on many different host platforms, including x86, PPC, Alpha, Sun, and MIPS |