Linux:32/64位程序(应用程序、共享库、内核模块)
摘要:
Linux系统区分32/64位,相应地,应用程序、共享库和内核模块也区分32/64位。
本文以Ubuntu系统为例,介绍如何编译和使用32/64位的应用程序、共享库和内核模块。
1. 应用程序
要点:
- 使用gcc编译器的-m32和-m64选项指定编译成32位或64位应用程序,编译时需要使用32/64位库,因此编译前需要安装对应的库。
- 在64位系统上,可以执行64位和32位应用程序。在32位系统上,只能执行32位应用程序,不能执行64位应用程序。
1.1 64位系统上编译应用程序
在64位系统上,gcc默认编译成64位程序,但可以编译32位程序,需要安装32位库。
安装32位库 :sudo apt-get install lib32readline-gplv2-dev
编译32位程序:gcc -m32 t1.c
1.2 32位系统上编译应用程序
在32位系统上,gcc默认编译32位程序,但可以编译64位程序,需要安装64位库。
安装64位库:sudo apt-get install lib64readline-gplv2-dev
编译64位程序:gcc -m64 t1.c
2. 共享库(so)
要点:
- 可以使用gcc的-m32和-m64选择编译32位或64位共享库(so)。
- 64位应用程序只能调用64位共享库,32位应用程序只能调用32位共享库。
参考:http://blog.csdn.net/wsl888444/article/details/8289056
2.1 编写共享库
// test.h 共享库接口文件
#ifndef _TEST_H_
#define _TEST_H_
void test( int x );
#endif
// test.c 共享库实现文件
#include <stdio.h>
void test( int x )
{
printf( "hello, I'm libtest.so %d\n", x );
return;
}
2.2 编译共享库
gcc test.c -fPIC -shared -o libtest.so [ -m32 | -m64 ]
| 选项 | 说明 |
|---|---|
| -fPIC | 表示编译为位置独立的代码。如果不用此选项,编译后的代码是位置相关的,则动态载入时是通过代码拷贝的方式来满足不同进程的需要,不能达到代码段共享的目的。 |
| -shared | 表示编译成共享库 |
| -m32 或 -m64 | 选择编译32位或64位共享库 |
2.3 使用共享库
2.3.1 编译应用程序时使用共享库
// t1.c 应用程序
#include "test.h"
int main( )
{
test( 99 );
return 0;
}
编译程序:
gcc t1.c -L . -l test -o t1 [ -m32 | -m64 ]
| 选项 | 说明 |
|---|---|
| -L | 指明共享库所在的目录 |
| -l | 指明共享库的名称,该名称是处在头lib 和后缀.so 中的名称。例如上面共享库libtest.so,则参数为 -l test 。 |
查看应用程序依赖的共享库: ldd t1
查看目标文件中定义的符号: nm t1
执行程序:
- 创建共享库文件的软链接:进入/usr/lib目录,创建到共享库的软链接。
例如共享库是/home/test/libtest.so,则命令是 ln -s /home/test/libtest.so libtest.so - 执行应用程序: ./t1
2.3.2 动态加载方式使用共享库
// t2.c 应用程序
int main( )
{
void *handle = NULL;
void (*test)( int x );
handle = dlopen( "./libtest.so", RTLD_LAZY );
if ( handle == NULL )
{
printf( "dll loading error.\n" );
return 0;
}
test = ( void(*)( int ) )dlsym( handle, "test" );
if ( test == NULL )
{
printf( "%s: dlsym: '%s'\n", "test", dlerror() );
return 0;
}
test( 99 );
return 0;
}
编译程序:
gcc -ldl test1.c –o test [ -m32 | -m64 ]
| 选项 | 说明 |
|---|---|
| -ldl | 使用共享库相关函数需使用该参数 |
**程序说明:**
使用C++时,so的头文件中声明前要加 extern "C",才能正确获取函数地址。否则,在dlsym可能产生错误:找不到函数(undefined symbol)。 test.h 中声明如: extern "C" void test( int x );
2.4 混合使用32/64位应用程序和共享库
问题: 32/64位应用程序是否可以调用64/32位共享库?
回答: 64位应用程序只能调用64位共享库,32位应用程序只能调用32位共享库。
参考:
http://cboard.cprogramming.com/linux-programming/113856-loading-32-bit-library-into-64-bit-linux-program.html
http://stackoverflow.com/questions/10039401/use-32bit-shared-library-from-64bit-application
解决方法:
- 方法一:编译使应用程序和共享库的位数相同
- 方法二:做一个与共享库位数相同的中间程序,用于调用共享库;应用程序与中间程序通信,间接调用共享库。参考我的另一篇文章:《Linux:使用rpcgen实现64位程序调用32位库函数》
3 内核模块(ko)
要点:
- 编译内核模块时,根据使用的内核头文件,决定生成的是32位或64位内核模块ko。
- 内核模块ko的运行不仅要求对应的Linux内核位数正确,而且要求Linux内核版本与编译内核模块时使用的内核头文件版本一致。
参考:http://blog.csdn.net/gavin_dinggengjia/article/details/6307080
3.1 什么是内核模块?
内核模块的全称是 Loadable Kernel Module(LKM, 动态可加载内核模块),它是Linux内核向外部提供的一个插口。
内核模块是具有独立功能的程序,通常由一组函数和数据结构组成,用来实现一种文件系统、一个驱动程序,或其它内核上层的功能。
内核模块可以被单独编译,运行时被链接到内核,作为内核的一部分在内核空间运行,这与运行在用户空间的进程不同。下表比较了应用程序与内核模块的差别。
| 项目 | C语言应用程序 | 内核模块 |
|---|---|---|
| 使用函数 | libc库 | 内核函数 |
| 运行空间 | 用户空间 | 内核空间 |
| 入口函数 | main() | module_init() |
| 出口函数 | exit() | module_exit() |
| 编译 | gcc -c | Makefile |
| 连接 | gcc | insmod |
| 运行 | 直接运行 | insmod |
| 调试 | gdb | kdbug、kdb、kgdb |
从表中可以看出,内核模块不能调用 libc 库函数,它运行在内核空间,只有超级用户可以对其运行。
另外,内核模块程序必须通过 module_init() 和 module_exit() 函数来告诉内核“我来了”和“我走了”。
3.2 编写一个简单的内核模块
内核模块和内核都在内核空间运行,内核模块编程在一定意义上说就是内核编程。
因为内核版本的每次变化,其中的某些函数名也会相应地发生变化,因此内核模块编程与内核版本密切相关。
1. 内核模块代码
// hello.c 内核模块代码
#include "linux/init.h" // 包含宏_init和_exit
#include "linux/kernel.h" // 包含常用的内核函数
#include "linux/module.h" // 所有模块都要用到
static int __init hello_init( void )
{
printk( KERN_ALERT "Hello world!\n" );
return 0;
}
static void __exit hello_exit( void )
{
printk(KERN_ALERT "Goodbye!\n");
}
module_init( hello_init );
module_exit( hello_exit );
MODULE_LICENSE( "GPL" );
MODULE_AUTHOR( "ddk" );
MODULE_DESCRIPTION( "hello" );
| 函数 | 说明 |
|---|---|
| module_init | 内核模块初始化的入口点 |
| module_exit | 注销由内核模块提供的所有功能 |
| hello_init | 内核模块初始化函数 |
| hello_exit | 内核模块的退出清理函数,可做终止该内核模块相关的清理工作。 |
| printk | 内核定义的函数,功能与printf类似,printk把要打印的信息输出到终端或系统日志。 |
2. Makefile
# Makefile
obj-m:=hello.o
KERNELBUILD:=/lib/modules/$(shell uname -r)/build
default:
make -C $(KERNELBUILD) M=$(shell pwd) modules
clean:
rm -rf *.o *.ko *.mod.c .*.cmd *.markers *.order *.symvers .tmp_versions
| 选项 | 说明 |
|---|---|
| obj-m | 决定过了内核模块的名称和生成的ko文件名 |
| KERNELBUILD | 编译内核模块需要的内核源代码文件目录 |
| M | 内核模块代码目录 |
| make -C ...... | 编译内核模块。-C 将工作目录转到KERNELBUILD,调用该目录下的Makefile,并向这个Makefile传递参数M的值是$(shell pwd) modules。 |
**关于KERNELBUILD的说明:**
(1)如果为Linux发行版(例如Ubuntu、CentOS等)编译内核模块,则可以直接从发行版目录 /usr/src 中获取这个目录,一般是 /usr/src/linux-headers-* 。这个目录区分32位和64位。
(2)如果为Linux标准内核(从 https://www.kernel.org/pub/linux/kernel/ 获取)编译内核模块,则需要先编译Linux标准内核,然后使用 /usr/src 中的编译后对应目录。Linux标准内核源代码不区分32位和64位,但编译时区分编译为32位或64位。编译和安装Linux标准内核,请参考:http://blog.csdn.net/ddk3001/article/details/50276347
(3)编译出的内核模块ko是32位或64位由下面决定:1、使用的内核源代码目录是32位或64位;2、编译时make命令中指定 ARCH=i386 或 ARCH=x86_64 。
(4)cat hello.ko可以查看内核模块要在哪个Linux内核版本中运行。
3. 编译和使用内核模块
| 功能 | 命令 | 说明 |
|---|---|---|
| 编译模块 | make | 执行第一个目标default,生成hello.ko,这个就是我们需要的内核模块。 |
| 编译清理 | make clean | 清理编译产生的文件,hello.ko 也会清理掉。 |
| 插入模块 | sudo insmod ./hello.ko | 用dmesg就可以看到产生的内核信息,Hello world! 内核消息也会输出到日志文件/var/log/kern.log中。 |
| 卸载模块 | sudo rmmod hello | 用dmesg可以看到Goodbye! |
3.3 modutils软件包
modutils是管理内核模块的一个软件包,安装后在/sbin目录下就会有insomod、rmmod、lsmod等实用程序。通常在加载Linux内核时,modutils已经被载入。
| 命令 | 说明 |
|---|---|
| insmod | 调用insmod程序把需要插入的模块以目标代码的形式插入到内核中。在插入的时候,insmod自动调用module_init()函数运行。 |
| rmmod | 调用rmmod程序将已经插入内核的模块从内核中移出。rmmod会自动运行module_exit()函数。 |
| lsmod | 调用lsmod程序将显示当前系统中正在使用的模块信息。实际上这个程序的功能就是读取/proc/modules中的信息。 |
| modinfo | 显示一个模块的相关信息。 |
| depmod | 生成可载入模块的依赖性文件,供modprobe在安装模块时使用。 |
| modprobe | modprobe 和 insmod 都是载入内核模块,差别是 modprobe 能够自动处理模块载入的依赖问题。modprobe 使用depmod生成的依赖性文件,从预定义目录树的一套模块中自动载入相关模块。 |
Linux:32/64位程序(应用程序、共享库、内核模块)的更多相关文章
- 使用VS2008,VS2010编译64位的应用程序
要编译生成64位的应用程序,就必须把vs2008,或vs2010的配置管理器设置为x64. 如果你的配置管理器那里没有x64这个选项,那么是你在安装vs时可能没有安装这个组件.你不用卸载vs,只需打开 ...
- 关于Qt 5-MSVC 2015 64位在 win7 64位系统debug程序崩溃的问题
关于Qt 5-MSVC 2015 64位在 win7 64位系统debug程序崩溃的问题 在win7 64位系统安装VC2015的编译器,并安装了 Qt 5.6 -5.7 VC2015 64位版本测 ...
- Adobe Photoshop CC 2018 v19.0 简体中文正式版下载安装破解(附注册机+破解教程) 32/64位(安装破解注意事项是什么)
Adobe Photoshop CC 2018 v19.0 简体中文正式版下载安装破解(附注册机+破解教程) 32/64位(安装破解注意事项是什么) 一.总结 一句话总结:下载安装破解教程文中都有,需 ...
- windows 7(32/64位)GHO安装指南(序篇)~
大家好,本人是高三刚毕业,即将踏入校园的程序猿~我写这篇文章呢,主要是想巩固一下之前对于电脑的基础知识理论,也希望能帮助没有电脑基础的同学能维护一下自己的电脑,要是能帮助女生修电脑那就是更好啦~~哈哈 ...
- VRay 2.0 SP1 2.10.01 for 3ds max 9/2008/2009/2010/2011/2012 32/64位 顶渲简体中文版+英文版[中国室内设计论坛-室内人]
VRay 2.0 SP1 2.10.01 for 3ds max 9/2008/2009/2010/2011/2012 32/64位 顶渲简体中文版+英文版[中国室内设计论坛-室内人] 对最新版本的V ...
- 【Win7激活工具2013版下载】适用于旗舰版、家庭高级版等所有版本32/64位 OEM激活
虽然现在Win8已经发布了,但是身边总是还有一些朋友在用着Win7系统,而近期微软频繁的推送补丁包,导致之前的那些激活都失效了.找了网络上很多工具,之前的那些有的已经不能用了,激活不了,今天就推荐一些 ...
- 检测dll是32/64位 ?
检测dll是32/64位 ? void CCheck32Or64Dlg::OnButton2() { CString fileName = ""; CFileDialog *fil ...
- 开源一个IE下获取XPath小工具,支持32/64位
背景是曾经友情支持了测试组一小段时间,发现他们使用selenium做页面的自动化测试,需要用到XPath,但IE下没有获取XPath的工具,只能在Firefox和chrome下获取,步骤还比较麻烦.而 ...
- IE下获取XPATH小工具,支持32/64位
背景是曾经友情支持了测试组一小段时间,发现他们使用selenium做页面的自动化测试,需要用到XPath,但IE下没有获取XPath的工具,只能在Firefox和chrome下获取,步骤还比较麻烦.而 ...
随机推荐
- 【笔试面试】神马搜索C++程序猿电话面试
面试时间:2015.07.15 预约时间:2015.07.14.电话面试前一天,会电话咨询你方面电话面试的时间. 面试环节: 无自我介绍(这是我面试这么多家公司碰到的第一次),直接面试内容. 问题1: ...
- ios开发之--NSNumber的使用
什么是NSNumber? NSArray/NSDictionary中只能存放oc对象,不能存放基本数据类型,如果想把基本数据类型放进去,需要先把基本数据类型转换成OC对象, 代码如下: ; ; flo ...
- 【NGINX】Windows配置
缺省安装nginx之后的配置 检查80端口占用 启动缺省配置之后的nginx 配置多端口站点 注册Server,server_name是配置的域名,proxy_pass是上图配置的代理地址 注意: 1 ...
- windows恶意软件删除工具(MRT.exe)检查计算机是否感染病毒使用图解
Microsoft Windows恶意软件删除工具可以检查运行 Windows XP.Windows 2000 和 Windows Server 2003 的计算机是否受到特殊.流行的恶意软件(包括 ...
- 使用 urllib 发送请求
urllib.request.urlopen(url, data=None, timeout=n) 用于发送HTTP请求并得到响应内容 In []: import urllib.request In ...
- 使用react进行父子组件传值
在单页面里面,父子组件传值是比较常见的,之前一直用vue开发,今天研究了一下react的父子组件传值,和vue差不多的思路,父组件向子组件传值,父通过初始state,子组件通过this.props进行 ...
- iOS开发——iOS7(及以后版本) SDK自带二维码(含条形码)扫码、二维码生成
本文转载至 http://www.cnblogs.com/leotangcn/p/4357907.html 现在很多APP都涉及了二维码扫码功能,这个功能简单实用,很多情况下用户乐于使用,现在本文带来 ...
- android中:/system/bin/sh: : No such file or directory错误
将一个raspberry下编译好的可执行文件放在android的system/bin下,修改为777权限,运行,出现下面的错误: /system/bin/sh: XXX: No such file o ...
- django进阶-小实例
前言: 这篇博客对上篇博客django进阶作下补充. 一.效果图 前端界面较简单(丑),有两个功能: 从数据库中取出书名 eg: 新书A 在form表单输入书名,选择出版社,选择作者(多选),输入完毕 ...
- Android Studio 3.0.1 版本包下载
Android Studio 3.0.1 发布了,这是对 Android Studio 3.0 的一个小的更新,包括一般错误修复和性能改进 下载地址: Windows 64 位:https://dl. ...