gas学习

来源:互联网 发布:狼雨seo团队 编辑:程序博客网 时间:2024/04/29 22:07
1. 入门
1.1 基本gas程序模板
1.2 gas汇编程序伪指令
1.3 gas的标签
1.4 gas的开始标签
1.5 gas中的系统调用
1.6 基本 AT&T 汇编风格
2. 使用标准C库函数
3. 定义数据元素
3.1 定义数据元素的命令
3.2 赋值命令
3.3 bss段
3.4 .fill 命令
4. MOV命令

1. 入门

利用 cpuid 取得 intel 集容cpu的厂商信息。

.section .dataoutput1:        .ascii "当前CPU厂商ID是:"output2:        .ascii "xxxxxxxxxxxx\n".section .text.global _start_start:        movl $0,%eax        cpuid        movl $output2,%edi        movl %ebx,(%edi)        movl %edx,4(%edi)        movl %ecx,8(%edi)        movl $4,%eax        movl $1,%ebx        movl $output1,%ecx        movl $(output2-output1+14),%edx        int $0x80        movl $1,%eax        movl $0,%ebx        int $0x80


编译和链接上面的源代码并运行:

as -o cpuid.o cpuid.s # 汇编源代码为目标文件ld -o cpuid cpuid.o # 链接目标文件为linux可执行的文件./cpuid # 执行

1.1 基本gas程序模板

gas程序分为几个部分,通常有data段和text段。data段存放数据,其 内容会被放在最终的可执行程序中。text段是汇编指令。通常还有 bss段,这里相当于缓存,临时创建。

.section .data    ....section .text    ...

1.2 gas汇编程序伪指令

一般汇编程序本身会提供一些方便的"指令",但是这些"指令"不是 cpu指令,它们只是方便汇编程序开发者,解释权归汇编程序本身。

gas中的“伪指令”都是以 "." 开头,如上面示例中的一些伪指令:

.section     定义一个段.data        同.section一起定义数据段.ascii       定义一个字符串.text        同.section一起定义程序段.global      定义全局标签

1.3 gas的标签

在gas中的标签等价于一个内存地址,相当于C语言中的指针。不过C语 言的指针还有数据类型属性,这里的数据类型需要自己指定了。

gas中的标签是以冒号结尾的字符串。如示例中的:

output1:output2:

既然gas中的标签是内存地址,这是一个数值。那么,我们可以在gas 程序中对标签进行算术运算,且对于“立即数”能出现的地方,标签也 都可以出现:

movl $(output2-output1+14),%edx

1.4 gas的开始标签

如果用 ld 手动链接程序,则需要在汇编程序中设置一个为 _start: 的开始标签,相当于C程序中的main函数。如果用gcc编译汇编程序, 那么要将 "_start:" 换成 "main:"

如果没有指定 "_start" 标签,可以在运新 ld 命令的时候指定开始标签:

ld -e

1.5 gas中的系统调用

Linux下的汇编程序可以使用系统调用,这样可以避免很多复杂的工作。 在gas里使用系统调用就是在相关寄存器存入系统调用号、调用函数的 参数,再执行 "int $0x80" 命令就可以了。

上例使用了两个系统调用函数: write 和 exit

1.6 基本 AT&T 汇编风格

  • 立即数 表示立即数要用"$"符号
  • 寄存器 表示寄存器要用"%"符号
  • 内存寻址 内存地址要放在寄存器里,才能被寻址,这是intel的cpu指令集规定的。
movl %ebx,(%edi)  # 将ebx里面的内容放到edi指向的内存地址单元处。movl %edx,4(%edi) # 将edx里面的内容放到比edi指向的内存地址高4个值的内存单元处。

2. 使用标准C库函数

使用标准C库函数的 cpuid2.s 程序:

.section .dataoutput:        .asciz "当前CPU厂商信息是:%s \n".section .bss        .lcomm buffer,12.section .text.global _start_start:        movl $0,%eax        cpuid        movl $buffer,%edi        movl %ebx,(%edi)        movl %edx,4(%edi)        movl %ecx,8(%edi)        pushl $buffer        pushl $output        call printf        addl $8,%esp        pushl $0        call exit


汇编、链接并运行:

as -o cpuid2.o cpuid2.sld -dynamic-linker /lib/ld-linux.so.2 -o cpuid2 -lc cpuid2.o

参数说明:

-lc 链接C库/lib/libc.so;如果是-lx,默认链接/lib/libx.so。-dynamic-linker /lib/ld-linux.so.2 使用/lib/ld-linux.so.2加载共享库。

3. 定义数据元素

3.1 定义数据元素的命令

.ascii     文本字符串.asciz     带零结束符的文本字符串.byte      字节值.double    双精度值.float     单精度值.int       32位整数.long      同.int.octa      16字节长度整数.quad      8字节长整数.short     16位整数.single    同.float

有几种数据段:

.section .data    定义通常的数据段,数据被包含在最终程序中.section .rodata  同.data,但是这里定义的数据的值不可修改.section .bss     相当于缓冲

数据定义可以一个标签一个命令一个数据的定义:

output:    .asciz "这是一个.asciz定义的字符串"value:    .int  100

也可以,一个标签一个命令定义一堆数据:

values:    .int 15,20,25,30,35,40,45,50,55,60

无论是哪种形式定义的,数据在内存中都是一个挨着一个的存放的。 这样我们可以用索引来引用它们。

3.2 赋值命令

gas中也可以用一个符号代表一个值,但是符号只不可修改:

.equ factor,3.equ LINUX_SYS_CALL,0x80

3.3 bss段

这个段无须声明特定的类型,只要声明大小:

.comm  声明未初始化数据的通用内存区域.lcomm 声明未初始化数据的"本地"通用内存区域

例如,声明一个1000字节的缓冲区,通过buffer引用这个区域的基址:

.section .bss  .lcomm buffer,1000

3.4 .fill 命令

这个命令让汇编器自动创建一段内存区域,并用0填充:

.section .databuffer:    .fill 1000

4. MOV命令

gas中把mov命令加了不同后缀,每个后缀表示操作不同的数据大小:

movl  32位movw  16movb  8

下面一个例子把一个值移到ecx寄存器,然后调用linux系统的exit正 常退出。用gdb可以看见寄存器的变化。

# 程序 movetest1.s.section .datavalue:        .int 1.section .text.global _start_start:        nop        movl value,%ecx        movl $1,%eax        movl $0,%ebx        int $0x80

用-gtabs参数汇编程序并链接:

as -gtabs -o movetest1.o movetest1.sld -o movetest1 movetest1.o

使用gdb调试程序:

root@jianlee:~/lab/asm# gdb -q movetest1(gdb) break *_start+1Breakpoint 1 at 0x8048075: file movetest1.s, line 8.(gdb) runStarting program: /root/lab/asm/movetest1Breakpoint 1, _start () at movetest1.s:88        movl value,%ecxCurrent language:  auto; currently asm(gdb) print/x %ecxA syntax error in expression, near `%ecx'.(gdb) print/x $ecx$1 = 0x0(gdb) next_start () at movetest1.s:99        movl $1,%eax(gdb) print/x $ecx$2 = 0x1(gdb) s_start () at movetest1.s:1010        movl $0,%ebx(gdb) contContinuing.Program exited normally.(gdb)

把寄存器的值传到内存里:

# movetest2.s 把寄存器的值传到内存中.section .datavalue:        .int 1.section .text.global _start_start:        nop        movl $100,%eax        movl %eax,value        movl $1,%eax        movl $0,%ebx        int $0x80

调试程序,查看程序执行过程:

root@jianlee:~/lab/asm# as -gtabs -o movetest2.o movetest2.smovetest2.s: Assembler messages:movetest2.s:0: Warning: end of file not at end of a line; newline insertedroot@jianlee:~/lab/asm# ld -o movetest2 movetest2.oroot@jianlee:~/lab/asm# gdb -q movetest2(gdb) break *_start+1Breakpoint 1 at 0x8048075: file movetest2.s, line 9.(gdb) runStarting program: /root/lab/asm/movetest2Breakpoint 1, _start () at movetest2.s:99        movl $100,%eaxCurrent language:  auto; currently asm(gdb) print/x $eax$1 = 0x0(gdb) x/d &value0x804908c <value>:1(gdb) s_start () at movetest2.s:1010        movl %eax,value(gdb) print/x $eax$2 = 0x64(gdb) x/d &value0x804908c <value>:1(gdb) s_start () at movetest2.s:1212        movl $1,%eax(gdb) x/d &value0x804908c <value>:100(gdb) contContinuing.Program exited normally.(gdb)

original link:http://jianlee.ylinux.org/Computer/%E6%B1%89%E5%AD%97%E7%B3%BB%E7%BB%9F/gas%E5%AD%A6%E4%B9%A0.html

write
exit

write

eax调用号4ebx将要写入的文件的文件描述符ecx需要写的字符串的内存起始地址edx需要写的字符串的长度
movl $4,%eaxmovl $1,%ebxmovl $output,%ecxmovl $14,%edxint $0x80

这个例子是将内存地址为output长度为14字节的字符串写到标准输出 (linux下标准输出的文件描述符是1)。

exit

eax1ebx退出状态数字
movl $1,%eaxmovl $0,%ebxint 0x80

这个例子是返回退出状态号0。通常这代表程序正常结束。



MBR原理
结构
分区表结构
Linux下备份修复mbr
备份
修复
修复分区表

MBR原理

结构

偏移值    内容0000      MBR程序代码01BE      分区表(4个分区,每个16字节)01FE      结束标志(aa55)

分区表结构

每个分区表都有16字节的大小。它的结构如下:

单位:字节1     如果是引导分区,值为80H;如果不是,值为00H2-4   该分区的起始扇区号5     标志字节      05  扩展分区      82  Linux交换分区      83  ext3分区      0c  fat32分区6-8   该分区的终止扇区号9-12  该分区已经使用的扇区数13-16 该分区总共占用的扇区数

Linux下备份修复mbr

备份

dd if=/dev/sda of=mbr.img bs=512 count=1

修复

dd if=mbr.img of=/dev/sda bs=512 count=1

修复分区表

dd if=mbr.img of=/dev/sda bs=512 skip=446 count=66