( 转 ) Linux内核中常用的汇编

AT&T 汇编语言的相关知识

在 Linux 源代码中,以 .S 为扩展名的文件是“纯”汇编语言的文件。这里,我们结合具体的例子再介绍一些 AT&T 汇编语言的相关知识。

1 . GNU 汇编程序 GAS ( GNU Assembly 和连接程序

当你编写了一个程序后,就需要对其进行汇编( assembly )和连接。在 Linux 下有两种方式,一种是使用汇编程序 GAS 和连接程序 ld ,一种是使用 gcc 。我们先来看一下 GAS 和 ld:

GAS 把汇编语言源文件( .o )转换为目标文件( .o ),其基本语法如下:

as filename.s -o filename.o

一旦创建了一个目标文件,就需要把它连接并执行,连接一个目标文件的基本语法为:

ld filename.o -o filename

这里 filename.o 是目标文件名,而 filename 是输出 ( 可执行 ) 文件。

GAS 使用的是 AT&T 的语法而不是 Intel 的语法,这就再次说明了 AT&T 语法是 Unix 世界的标准,你必须熟悉它。

如果要使用 GNC 的 C 编译器 gcc ,就可以一步完成汇编和连接,例如:

gcc -o example example.S

这里, example.S 是你的汇编程序,输出文件(可执行文件)名为 example 。其中,扩展名必须为大写的 S ,这是因为,大写的 S 可以使 gcc 自动识别汇编程序中的 C 预处理命令,像 #include 、 #define 、 #ifdef 、 #endif 等,也就是说,使用 gcc 进行编译,你可以在汇编程序中使用 C 的预处理命令。

2.  AT&T 中的节( Section )

在 AT&T 的语法中,一个节由 .section 关键词来标识,当你编写汇编语言程序时,至少需要有以下三种节:

.section .data : 这种节包含程序已初始化的数据,也就是说,包含具有初值的那些变量,例如:

hello      : .string "Hello world!/n"

hello_len : .long 13

.section .bss :这个节包含程序还未初始化的数据,也就是说,包含没有初值的那些变量。当操作

系统装入这个程序时将把这些变量都置为 0 ,例如:

name      : .fill 30   # 用来请求用户输入名字

name_len  : .long  0   # 名字的长度 ( 尚未定义 )

当这个程序被装入时, name 和 name_len 都被置为 0 。如果你在 .bss 节不小心给一个变量赋了初值,这个值也会丢失,并且变量的值仍为 0 。

使用 .bss 比使用 .data 的优势在于, .bss 节不占用磁盘的空间。在磁盘上,一个长整数就足以存放 .bss 节。当程序被装入到内存时,操作系统也只分配给这个节 4 个字节的内存大小。

注意:编译程序把 .data 和 .bss 在 4 字节上对齐( align ),例如, .data 总共有 34 字节,那么编译程序把它对其在 36 字节上,也就是说,实际给它 36 字节的空间。

.section .text :这个节包含程序的代码,它是只读节,而 .data 和 .bss 是读/写节。

3 .汇编程序指令( Assembler Directive )

上面介绍的 .section 就是汇编程序指令的一种, GNU 汇编程序提供了很多这样的指令( directiv ),这种指令都是以句点( . )为开头,后跟指令名(小写字母),在此,我们只介绍在内核源代码中出现的几个指令(以 arch/i386/kernel/head.S 中的代码为例)。

( 1 ) ascii "string"...

.ascii 表示零个或多个(用逗号隔开)字符串,并把每个字符串(结尾不 自动加“ 0 “字节)中的字符放在连续的地址单元。

还有一个与 .ascii 类似的 .asciz , z 代表“ 0 “,即每个字符串结尾自动加一个” 0 “字节,例如:

int_msg:

.asciz "Unknown interrupt/n"

( 2 ) .byte 表达式

.byte 表示零或多个表达式(用逗号隔开),每个表达式被放在下一个字节单元。

( 3 ) .fill 表达式

形式: .fill repeat , size , value

其中, repeat 、 size 和 value 都是常量表达式。 Fill 的含义是反复拷贝 size 个 字节。 Repeat 可以大于等于 0 。 size 也可以大于等于 0 ,但不能超过 8 ,如果超过 8 ,也只取 8 。把 repeat 个 字节以 8 个为一组,每组的最高 4 个字节内容为 0 ,最低 4 字节内容置为 value 。

Size 和 value 为可选项。如果第二个逗号和 value 值不存在,则假定 value 为 0 。如果第一个逗号和 size 不存在,则假定 size 为 1 。

例如,在 Linux 初始化的过程中,对全局描述符表 GDT 进行设置的最后一句为:

.fill NR_CPUS*4,8,0              /* space for TSS's and LDT's */

因为每个描述符正好占 8 个字节,因此, .fill 给每个 CPU 留有存放 4 个描述符的位置。

( 4 ) .globl symbol

.globl 使得连接程序( ld )能够看到 symbl 。如果你的局部程序中定义了 symbl ,那么,与这个局部程序连接的其他局部程序也能存取 symbl ,例如:

.globl SYMBOL_NAME( idt)

.globl SYMBOL_NAME( gdt)

定义 idt 和 gdt 为全局符号。

( 5 ) quad bignums

.quad 表示零个或多个 bignums (用逗号分隔),对于每个 bignum ,其缺省值是 8 字节整数。如果 bignum 超过 8 字节,则打印一个警告信息;并只取 bignum 最低 8 字节。

例如,对全局描述符表的填充就用到这个指令:

.quad 0x00cf9a000000ffff        /* 0x10 kernel 4GB code at 0x00000000 */

.quad 0x00cf92000000ffff        /* 0x18 kernel 4GB data at 0x00000000 */

.quad 0x00cffa000000ffff        /* 0x23 user   4GB code at 0x00000000 */

.quad 0x00cff2000000ffff        /* 0x2b user   4GB data at 0x00000000 */

( 6 ) rept count

把 .rept 指令与 .endr 指令之间的行重复 count 次,例如

.rept   3

.long   0

.endr

相当于

.long   0

.long   0

.long   0

( 7 ) space size , fill

这个指令保留 size 个 字节的空间,每个字节的值为 fill 。 size 和 fill 都是常量表达式。如果逗号和 fill 被省略,则假定 fill 为 0 ,例如在 arch/i386/bootl/setup.S 中有一句:

.space  1024

表示保留 1024 字节的空间,并且每个字节的值为 0 。

( 8 ) .word expressions

这个表达式表示任意一节中的一个或多个表达式(用逗号分开),表达式的值占两个字节,例如:

gdt_descr:

.word GDT_ENTRIES*8-1

表示变量 gdt_descr 的置为 GDT_ENTRIES*8-1

( 9 ) .long expressions

这与 .word 类似

( 10 ) .org new-lc , fill

把当前节的位置计数器提前到 new-lc ( new location counter )。 new-lc 或者是一个常量表达式,或者是一个与当前子节处于 同一节的表达式。也就是说,你不能用 .org 横跨节:如果 new-lc 是个错误的值,则 .org 被忽略。 .org 只能增加位置计数器的值,或者让其保持不变;但绝不能用 .org 来让位置计数器倒退。

注意,位置计数器的起始值 是相对于一个节的开始的,而不是子节的开始。当位置 计数器被提升后,中间位置的字节被填充值 fill (这也是一个常量表达式)。如果逗号和 fill 都省略,则 fill 的缺省值为 0 。

例如: .org 0x2000

ENTRY( pg0)

表示把位置计数器置为 0x2000 ,这个位置存放的就是临时页表 pg0 。

转自:http://www.linuxidc.com/Linux/2009-12/23456p3.htm

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值