IA32架构CPU下的汇编编程学习
通常掌握某一特定机器的汇编编程技术需要一定的时间。然而,如果掌握其他处理器的汇编编程(例如ARM,MIPS等),那么学习IA32结构CPU下的汇编编程将会省去很多时间。以下对IA32架构下的汇编语言编程进行简单的总结,方便以后回头来温习
1.指令语法
关于IA32架构的CPU的汇编语言的语法和表示有两种约定:Intel和AT&T,大多数的文件使用Intel的约定,而GNU汇编器使用AT&T的约定,这两种约定之间主要的不同如下表所示:
|
GNU 语法(AT&T) |
Intel |
立即数 |
前面需要加上"$"
例如:push $4
movl $0xd00a, %eax |
没有限制
例如:push 4
mov ebx d00ah |
寄存器 |
前面需要加上“%”
例如:%eax |
无限制
例如:eax |
参数顺序(例如:
把C变量“foo”加到
寄存器EAX中) |
source1, [source2,] dest
例如:addl $_foo, %eax |
des, source1 [,source2]
例如:add eax, _foo |
单操作数 |
指明操作数的大小(用{b, w, l})
例如:movb foo, %al |
用寄存器名间接的指明操作数的大小,
byte ptr, word ptr 和dword ptr
例如:mov al, foo |
寻址一个C变量"foo" |
_foo |
[_foo] |
寻址寄存器指定的内存(例如,EAX) |
(%eax) |
[eax] |
寻址寄存器中值的变量偏移值 |
_foo(%eax) |
[eax + _foo] |
寻址32-bit整数的数组"foo"中的值 |
_foo(,%eax,4) |
[eax * 4 + foo] |
等效于C代码中的*(p +1) |
1(%eax) |
如果EAX中存储的是p的值,则[eax + 1] |
2. 内存操作
IA32处理器使用分段内存架构,也就是说内存位置需要通过段选择子和偏移来确定。
- 段选择子指定包含操作数的段。
- 偏移(从段的开始位置到操作数所在位置的第一个byte的字节数)指定了操作数的线性地址或有效地址
3.经常使用的指令
下表中所示是一些经常使用的指令。
类别 |
指令 |
解释 |
数据转移
|
mov{l,w,b} source, dest
|
移动source到dest
|
xchg{l,w,b} dest1, dest2
|
交换
|
cmpxchg{l,w,b} dest1, dest2
|
比较和交换
|
push/pop{l,w}
|
入栈/出栈
|
movsb
|
移动DS:(E)SI 的bytes到地址ES:(E)DI处,典型的使用前缀rep
|
算术
|
add/sub{l,w,b} source, dest
|
加减
|
imul/mul{l,w,b} formats
|
有符号/无符号乘
|
idiv/div{l,w,b} dest
|
有符号/无符号除
|
inc/dec/neg{l,w,b} dest
|
增1/减1/取负
|
cmp{l,w,b} source1, source2
|
比较
|
逻辑
|
and/or/xor/not{l,w,b} source, dest
|
逻辑与/或/异或/非操作
|
sal/sar{l,w,b} formats
|
算术左移/右移
|
shl/shr{l,w,b} formats
|
逻辑左移/右移
|
控制转移
|
jmp address
|
无条件跳转
|
call address
|
保存EIP到堆栈中,然后跳转到address处
|
ret
|
返回到通过call调用保存的EIP处
|
leave
|
从堆栈中恢复EBP; pop off the stack frame
|
j{e,ne,l,le,g,ge} address
|
如果{=,!=,<,<=,>,>=},跳转到address处
|
loop address
|
对ECX或 CX进行减1操作;如果 = 0,则跳转
|
rep
|
重发串操作的前缀
|
int number
|
软件中断
|
iret
|
中断返回,EFLAGS 从堆栈中出栈
|
另外,用于长跳转的名字为ljmp,长调用为lcall
这里只列了一小部分的命令,IA32 Intel Architecture Software Developer's Manual, Volume 2的3.2节对IA32的所有指令进行了详细的描述,在Intel手册中使用的指令名字是按照Intel汇编语法约定的。
4.汇编指令
GNU汇编器指令名字以句点“.”开始,然后剩下的是小写字母,以下是常用的一些指令:
.ascii "string foo" 定义了ASCII串“string foo”
.asciz "string foo" 定义了ASCII串“string foo”,以0结尾
.string "string foo" 与.asicz "string foo"相同
.align 4 以双字边界来进行内存对齐
.byte 10, 13, 0 定义了三个字节
.word 0x0456, 0x1234 定义了两个字
.long 0x001234, 0x12345 定义了两个长字
.equ STACK_SEGMENT, 0X9000 设置符号STACK_SEGMENT的值为0x9000
.globl symbol 让“symbol”全局可见(对于定义全局标签和程序名字非常有用)
.code16 告诉汇编器插入适合的重写前缀以其运行在实模式下
5. 内联汇编(Inline Assembly)
通过gcc编译器生成的内联汇编代码的最基本的格式如下:
asm volatile("assembly-instruction");
assembly-instruction将会内联 到asm语句所在的地方,关键字volatile是可选的。该关键字告诉gcc编译器不要去优化该条指令。对于没有寄存器的内联汇编指令写起来非常的方便,例如:
asm volatile("cli");
用于禁止中断
asm volatile("sti");
用于开启中断
在C代码中编写内联汇编代码的通用格式如下:
asm [volatile] ("statements": output_regs: input_regs: used_regs);
其中statements是汇编指令, 如果有多于一条指令,可以使用“\n\t”来分开它们,让其看起来舒服点,
“input_regs”告诉gcc编译器哪个C变量移动到哪个寄存器,例如,想加载变量"foo"到寄存器EAX中,以及变量"bar"到寄存器ECX,可以些微:
:“a”(foo), "c"(bar)
gcc使用单个字母来表示所有的寄存器
单个字母 |
寄存器 |
a |
eax |
b |
ebx |
c |
ecx |
d |
edx |
S |
esi |
D |
edi |
I |
常数值(0到31) |
q |
从EAX,EBX,ECX,EDX分配一个寄存器 |
r |
从EAX,EBX,ECX,EDX,ESI,EDI中分配一个寄存器 |
"output_regs"提供了输出寄存器,一种方便的方法是让gcc编译器来选择寄存器,只需要指定“=q”或“=r”来让gcc编译器选择寄存器,可以通过利用“%0”来指定第一个分配的寄存器,“%1”指定第二个寄存器,等等。在汇编指令中,如果在输入寄存器列表中指定了寄存器。可以只需要“0”或“1”,不要前缀“%”
“used_regs”列出了在汇编代码中使用的寄存器。
下面给出了一段内联汇编包含在C代码中的例子。
asm ("leal (%1,%1,4), %0"
: "=r" (x_times_5)
: "r" (x) );
和
asm ("leal (%0,%0,4), %0"
: "=r" (x)
: "0" (x) );
6. 汇编程序结构和调用约定
最简单的学习汇编编程的方法是把简单的C程序编译为汇编源代码,该源代码将会显示常用的操作码,指令和寻址语法。这是一种有效的方法来学习汇编编程。
下面通过一个例如来说明汇编程序结构和调用约定,考虑如下的C程序hello.c
#include <stdio.h>
static char buf[4096];
int foo(int n)
{
return n - 1;
}
int main(void)
{
printf("Hello world\n");
return f00(5);
}
通过如下的命令对该C源代码进行编译
gcc -S hello.c
gcc编译器将会编译hello.c为汇编源代码hello.s,
以下是hello.s的源代码
.file "hello.c"
.local buf
.comm buf,4096,32
.text
.globl foo
.type foo, @function
foo:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
movq %rsp, %rbp
.cfi_offset 6, -16
.cfi_def_cfa_register 6
movl %edi, -4(%rbp)
movl -4(%rbp), %eax
subl $1, %eax
leave
ret
.cfi_endproc
.LFE0:
.size foo, .-foo
.section .rodata
.LC0:
.string "Hello world"
.text
.globl main
.type main, @function
main:
.LFB1:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
movq %rsp, %rbp
.cfi_offset 6, -16
.cfi_def_cfa_register 6
movl $.LC0, %edi
call puts
movl $5, %edi
movl $0, %eax
call f00
leave
ret
.cfi_endproc
.LFE1:
.size main, .-main
.ident "GCC: (Ubuntu 4.4.3-4ubuntu5.1) 4.4.3"
.section .note.GNU-stack,"",@progbits
可以编写一些其他的简单C代码,然后编译为汇编代码来查看汇编源代码
来自于http://zoo.cs.yale.edu/classes/cs422/2011/ref/pc-arch#memory
分享到:
相关推荐
YALE 人脸数据库,人脸识别的好工具,15个人,每个人11副图像-
Yale_64x64.mat
一个关于核pca的程序源代码,可用于人脸识别,里面包含orl32和yale32数据文件。
Yale_64x64数据集,包含15个人,每人11张图,均为PNG格式,64*64大小
yale 人脸库,里面有15个人脸类别,每个类别有11张人脸图像,这是比较简单的人脸库
ma yi sparse representation classification .EXTENDED YALE B database.recognition rate 95 。
是耶鲁大学的人脸库,耶鲁大学的人脸库分为A\B,这是A,B太大传不上来.
耶鲁大学实验室的人验库,包含了各种不同的表情,不同的姿态,对于研究人验识别的程序员来说,非常的有用。欢迎下载。
Yale_template.ipynb
基于Yale_CAS的单点登录的设计与实现,大学发表论文
Yale face in separate directory for each subject
MATLAB平台上先用pca降维之后的yale人脸识别算法
这是用于人脸识别的经典人脸库,人脸识别的实验和验证都是在这些基础库上完成的,它是yale人脸库,包含不同人脸的各种姿态
YALE人脸数据库(美国,耶鲁大学)由耶鲁大学计算视觉与控制中心创建,包含15个人,每个人有不同表情、姿态和光照下的11张人脸图像,共165张图片,每张图片大小为100*100。整个数据集非常小,图片信息也较为简单。
耶鲁大学人脸数据集 数据构成: 分为fea(人脸数据165x4096) gnd(标签165x1) 图像大小为64x64(64x64=4096) 一共15个人的人脸,每个人11条人脸数据
入门从Github的Releases选项卡下载最新版本: 解压缩发行版并将其移动到: /path/to/archivesspace/plugins解压缩: $ cd /path/to/archivesspace/plugins$ unzip yale_accession_marc_export-vX.X.zip通过编辑...
yale_marcxml2accession_extras 附加的 MARC XML -> 耶鲁的 Accession 映射 入门 从 Github 的 Releases 选项卡下载最新版本: 解压缩发行版并将其移动到: /path/to/archivesspace/plugins 解压: $ cd /path...
基于Yale人脸数据库的人脸识别,识别率达到90.67
YaleB_32x32,包含38个人,每人64张图,均为PNG格式,32*32大小