Linux内核0.12——内核编程语言和环境

/********AT&T 汇编格式********/

1、为了维持与gcc输出汇编程序的兼容性,as汇编器使用AT&T系统V的汇编语法,这里主要说明一下它与intel汇编的语法区别

2、AT&T与intel汇编语法格式的区别
1)寄存器引用:mov %eax,%ebx
2)操作数顺序:mov %eax(源),%ebx(目的)
3)立即数格式:mov $4,%ebx(如果不加$,则认为4是地址);mov value,%ebx(可以直接引用符号常数);mov $value,%ebx(引用了符号常数作为地址)
4)操作数长度:movb %eax,%ebx(movb为mov byte ptr,movw为mov word ptr,movl为mov long ptr)

5)跳转指令:ljmp $section,$offset;lcall $section,$offset;lret $stack_adjust(等同于intel汇编格式的:jmp far section:offset;call far section:offset;ret far stack_adjust)

6)内存引用:section:[base + index*scale + disp](等同于intel汇编:section:disp(base,index,scale))

/*********嵌入汇编********/

1、C程序的产生过程(gcc编译器):.c源文件----(cpp预处理)---->.c纯C----(cc编译器)---->.s汇编程序----(as汇编器)---->.o目标文件----(.a库文件+ld连接器)---->可执行文件

2、嵌入汇编格式:

__asm__("assemble language"
:output register
:input register
:to be changed register);
说明:1、为了让gcc编译产生的汇编程序中寄存器前面有一个%,在嵌入汇编语句中寄存器名称前需加两个%;2、输出寄存器格式为"=a"(__res),这是指将eax的值输出到__res变量中去,具体的Google。。。3、在前几个寄存器中已经包括了要被改变的寄存器的时候,就不要在要被改变的寄存器一项添加了

简单的strcpy函数代码:

char * strcpy(char * dest,const char * src)
{
__asm__("cld\n"
"1:\tlodsb\n\t"
"stosb\n\t"
"testb %%al,%%al\n\t"
"jne 1b"
::"S"(src),"D"(dest));
return dest;
}
3、C函数调用机制:“设置”,初始化栈帧结构;“主体”,执行函数的实际计算操作;“结束”,恢复栈状态并从函数中返回

4、C和汇编的互相调用:

在汇编中调用C:比较自由,只要是在栈中适当位置的内容就都可以作为参数供C函数使用;我们可以不用CALL指令而采用JMP指令来达到调用函数的目的

在C中调用汇编:方法和前者一样,重点仍然是对函数参数在栈中位置的确定上

/******目标文件格式及其链接*******/

1、目标文件组成(具体参见include/a.out.h文件):

依次序总的为:a.out文件头、代码部分、数据部分、代码重定位信息、数据重定位信息、符号表和字符串表

执行头部分:1)魔数字段值:0x107魔数OMAGIC指明文件是目标文件或者是不纯的可执行文件;0x10b魔数ZMAGIC指明文件为需求分页处理的可执行文件;2)a_text、a_data和a_bss分别指明后面只读的代码段、可读写的数据段和数据段后面未初始化数据区域的长度;3)a_entry指明了程序代码开始执行的地址;4)a_syms、a_trsize和a_drsize分别指明了数据段后面符号表、代码和数据段重定位信息的大小。

重定位信息部分:重定位信息为struct relocation_info{..}结构体;在代码段被重定位到不同的基地址处时,重定位项指出需要修改的地方;在模块文件中存在对未定义符号引用时,当此未定义符号最终被定义时连接程序就可以使用相应重定位项对符号值进行修改。

符号表和字符串部分:这是目标文件的最后部分;符号表记录项需要记录该符号的符号名、符号名字符串在字符串表中的偏移位置、符号的类型、是否为全局的、符号的值

2、查看目标文件中的具体值:

objdump -h hello.o
查看可执行文件的具体值:

objdump -h hello
3、链接程序的任务

1)给执行文件进行存储空间分配操作。一旦存储位置确定,链接程序就可以继续执行符号绑定操作和代码修正操作

2)把所有模块中相同类型的段组合连接在一起,在输出文件中为指定段类型形成单一一个段

4、内核加载可执行文件

1)首先,内核根据文件头部结构中的信息首先判断文件是不是一个合适的可执行文件

2)然后系统在用户态堆栈顶部为程序设置环境参数和命令行上输入的参数信息块并为其构建一个任务数据结构

3)接着在设置了一些相关寄存器值后利用堆栈返回技术去执行程序。执行程序映像文件的代码和数据将会在实际执行到或用到时利用需求加载技术动态加载到内存中

/*****makefile*****/

参见:http://blog.csdn.net/fengxiaoke_fxk/article/details/7525804


  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
ARM 是一种广泛使用的 CPU 架构,而 Linux 内核是一个开放源代码的操作系统内核。在 ARM 平台上,我们可以通过内核模块编程的方式与内核进行交互,实现一些自定义的功能。 下面,我们将介绍如何在 ARM Linux 上编写内核模块,并输出一个简单的 "Hello World" 消息。 ## 1. 环境准备 在开始编写内核模块之前,需要先准备好开发环境。具体步骤如下: 1. 安装交叉编译工具链。ARM 平台上的应用程序和内核模块需要使用交叉编译工具链进行编译。可以从官网下载对应的交叉编译工具链,也可以使用已经编译好的交叉编译工具链。 2. 下载内核源代码。可以从官网下载对应版本的内核源代码,也可以使用已经编译好的内核源代码。 3. 配置内核源代码。需要在内核源代码根目录下运行配置命令 `make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- menuconfig` 进行配置,选择需要的模块和功能。 ## 2. 编写内核模块 在准备好开发环境之后,可以开始编写内核模块了。具体步骤如下: 1. 创建一个新的文件夹,用于存放内核模块代码。 2. 创建一个新的 C 文件,命名为 `hello.c`。 3. 在 `hello.c` 文件中编写以下代码: ```c #include <linux/init.h> #include <linux/module.h> static int __init hello_init(void) { printk(KERN_INFO "Hello, world!\n"); return 0; } static void __exit hello_exit(void) { printk(KERN_INFO "Goodbye, world!\n"); } module_init(hello_init); module_exit(hello_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Your Name"); MODULE_DESCRIPTION("A simple hello world module"); ``` 这段代码定义了一个简单的内核模块,当模块加载时会输出 "Hello, world!" 消息,当模块卸载时会输出 "Goodbye, world!" 消息。 4. 使用交叉编译工具链进行编译。在终端中进入 `hello.c` 文件所在的文件夹,运行以下命令进行编译: ```bash arm-linux-gnueabi-gcc -Wall -Werror -O2 -o hello.ko -c hello.c ``` 这个命令将生成一个名为 `hello.ko` 的内核模块文件。 ## 3. 加载和卸载内核模块 在编写好内核模块后,我们需要将它加载到内核中进行测试。具体步骤如下: 1. 将 `hello.ko` 文件复制到 ARM Linux 系统上。 2. 在终端中进入 `hello.ko` 文件所在的文件夹,运行以下命令以加载内核模块: ```bash insmod hello.ko ``` 这个命令将调用内核中的 `init_module` 函数,执行 `hello_init` 函数,输出 "Hello, world!" 消息。 3. 查看系统日志,可以看到 "Hello, world!" 消息。 ```bash dmesg ``` 4. 在终端中运行以下命令以卸载内核模块: ```bash rmmod hello ``` 这个命令将调用内核中的 `cleanup_module` 函数,执行 `hello_exit` 函数,输出 "Goodbye, world!" 消息。 5. 再次查看系统日志,可以看到 "Goodbye, world!" 消息。 至此,我们已经成功地在 ARM Linux 上编写了一个简单的内核模块,并输出了 "Hello, world!" 消息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值