3.2程序编码

unix> gcc -01 -o p p1.c p2.c

-o用于指定输出(out)文件名。

-01,-02 告诉编译器使用第一级或第二级优化

3.2.1机器级代码

机器级编程两种重要的抽象:

1.ISA(指令集体系结构):机器级程序的格式和行为,叙述成按顺序执行,一条指令结束后,下一条再开始。

2.机器级程序使用的储存器地址是虚拟地址,提供的储存器模型看上去是一个非常大的字节数组。

IA32:

1.程序计数器

2.整数寄存器文件

3.条件码寄存器保存着最近执行的算术或逻辑指令的状态信息。

4.一组浮点寄存器存放浮点数据。

3.2.2代码示例

gcc  -S -o code.s code.c产生一个汇编文件code.svim code.s

objdump -d xxx.xx使用反汇编器查看目标代码文件的内容。

机器代码和它的反汇编表示的一些特性

1.IA32指令长度从1到15个字节不等

2.设计指令格式的方式是,从某个给定位置开始,可以将字节唯一的解码成机器指令

3.反汇编器只是基于机器代码文件中的字节序列来确定汇编代码,不需要访问程序的源代码或汇编代码

4.反汇编器使用的指令命名规则与GCC生成的汇编代码使用的有些差别

3.3数据格式

8 位:字节

16位:字

32位:双字

64位:四字

16位的机器体系结构,Intel用术语"字(word)"表示16位数据类型。

32位机器体系结构是从16位扩展过来,因此称32位数为“双字(double words)”,称64位数为“四字(quad words)”。

大部分指令都是针对字节和双字操作的。

C声明               Intel数据类型                          GAS后缀                                      大小(字节)

char                 字节(byte)                             b                                                       1

short                字(word)                               w                                                       2

int                    双字(double words)            l                                                        4

unsigned         双字(double words)            l                                                        4

long int           双字(double words)             l                                                        4

unsigned long    双字(double words)         l                                                        4

char *                  双字(double words)         l                                                        4

float                 单精度(signal)                      s                                                        4

double              双精度(double)                  l                                                         8

long double       扩展精度                                 t                                                     10/12

GAS中的每个操作指令都有一个字符后缀,用于表明操作数的大小。例如,mov有三种形式: movb(传送字节)、movw(传送字)、movl(传送双字)。其中float的后缀也是l,这不会与整数的混淆,因为浮点数使用的一组完全不同的指令和寄存器(浮点数寄存器)。

3.4访问信息

在IA32中央处理单元(CPU)中,包含了8个32位整数寄存器。在每个32位寄存器的名字前面都会有一个%e,在这里可以把e理解成extended(扩展的),因为早期的8086寄存器是16位,所以加e之后就变成32位的了。

3.4.1操作数指示符

操作数指示符包括立即数,寄存器,存储器。

类型

格式

操作数值

名称

立即数

$Imm

Imm

立即数寻址

寄存器

Ea

R[Ea]

寄存器寻址

存储器

Imm

M[Imm]

绝对寻址

存储器

(Ea)

M[R[Ea]]

间接寻址

存储器

Imm(Eb)

M[Imm + R[Eb]]

(基址+偏移量)寻址

存储器

(Eb, Ei)

M[R[Eb] + R[Ei]]

变址寻址

存储器

Imm(Eb, Ei)

M[Imm + R[Eb] + R[Ei]]

变址寻址

存储器

(, Ei, s)

M[R[Ei] * s]

比例变址寻址

存储器

Imm(, Ei, s)

M[Imm + R[Ei] * s]

比例变址寻址

存储器

(Eb, Ei, s)

M[R[Eb] + R[Ei]*s]

比例变址寻址

寄存器

Imm (Eb, Ei, s)

M[Imm + R[Eb] + R[Ei]*s]

比例变址寻址

3.4.2数据传送指令

将数据从一个位置复制到另一个位置的指令是最频繁使用的指令

传送指令MOV

MOV reg/mem,imm           ;立即数送寄存器或是存储器

MOV reg/mem/seg,reg      ;寄存器送寄存器(包括段寄存器)或贮存

MOV reg/seg,mem            ;主存送寄存器(包括段寄存器)

MOV reg/mem,seg            ;段寄存器送主存或寄存器

特别说明:(1)立即数传送至通用寄存器(不包括段寄存器)或存储单元

(2)IA32的限制:两个操作数都不能指向存储器。

3.5算术和逻辑操作

3.5.1加载有效地址    3.5.2一元和二元操作     3.5.3移位操作

加载有效地址指令leal 实际上是movl指令的变形,它的指令形式是从储存器读数据到寄存器,但实际上它没用引用储存器。

一元操作

只有一个操作数,既是源又是目的,可以是一个寄存器,或者存储器位置。

二元操作

操作数既是源又是目的

·第一个操作数可以是立即数、寄存器或者存储器位置 第二个操作数可以是寄存器或者存储器位置 但是不能同时是存储器位置。

移位操作

SAL 算术左移

SHL 逻辑左移

SAR 算术右移(补符号位)

SHR 逻辑右移(补0)

3.5.5特殊的算术操作

imull

双操作数,从两个32位操作数产生一个32位的乘积。

mull
         无符号数乘法

要求一个参数必须在寄存器%eax中,另一个作为指令的源操作数给出。乘积的高32位在%edx中,低32位在%eax中。

idivl

有符号除法

操作数

将DX:AX中的64位数作为被除数,操作数中为除数,结果商在AX中,余数在DX中。

divl无符号除法

通常会事先设定寄存器%edx为0.

3.6控制

3.6.1条件码

条件语句、循环语句和分支语句,要求有条件的进行,根据数据测试的结果来决定操作执行的顺序。机器代码提供两种基本的低级机制来实现有条件的行为:测试数据值,然后根据测试的结果来改变控制流或者数据流

控制指令-条件码

CPU维护着一组单个位的条件码寄存器,他们描述了最近的算术或者逻辑操作的属性。可以检测这些寄存器来执行条件分支指令

最常用的条件码:

CF:进位标志。最近的操作使最高位产生了进位。可以用来检查无符号操作数的溢出

ZF:零标志。最近的操作得出的结果为0.

SF:符号标志。最经的操作得到的结果为负数。

OF:溢出标志。最近的操作导致一个补码溢出——正溢出或者负溢出

比较和测试指令

有两类指令只设置条件码而不改变任何其他寄存器。

CMP指令根据两个操作数之间的差来设置条件码。

TEST指令的行为同and一样。典型的用法是,testl %eax,%eax用来检查%eax是负数、零还是正数

3.6.2访问条件码

三种方法

1.根据条件码的某个组合,将一个字节设置为0或者1

2.可以条件跳转到程序的某个其他的部分

3.可以有条件地传送数据

3.6.3、跳转指令及其编码

jump分为直接跳转和间接跳转

直接跳转:后面跟标号作为跳转目标

间接跳转:*后面跟一个操作数指示符

 

 

3.6.4翻译条件分支

将条件表达式和语句从c语言翻译成机器语言,最常用的方式就是结合有条件和无条件跳转

无条件跳转:例如 goto。书上的例子就是把if-else语句翻译成了goto形式,然后再由这个形式翻译成汇编语言。

3.6.5循环

1.Do-while循环

源代码

do{

body-statement 

}while(test-expr)

翻译成汇编的伪代码

loop:

         body-statement;

t = test-expr;

if(t)

goto loop;

2.While循环

源代码

while(test-expr)

body-statement

翻译成汇编的伪代码

t = test-expr;

if(!t)

goto done;

loop:

body-statement;

t = test-expr;

if(t)

goto loop;

done:

For循环

源代码:

for(init-expr;

test-expr;

update-expr)

body-statement;

翻译成汇编的伪代码:

init-expr;

t = test-expr;

if(!t)

goto done;

loop:

body-statement;

update-expr;

t = test-expr;

if(t)

goto loop;

done:

switch语句

根据一个整数索引值进行多重分支,执行switch语句的关键步骤是通过跳转表来访问代码位置,使结构更加高效。

3.7过程

数据传递、局部变量的分配和释放通过操纵程序栈来实现。

3.7.1栈帧结构

·      为单个过程分配的栈叫做栈帧,寄存器%ebp为帧指针,而寄存器指针%esp为栈指针,程序执行时栈指针移动,大多数信息的访问都是相对于帧指针。

·      栈向低地址方向增长,而栈指针%esp指向栈顶元素。

3.7.2转移控制

call:目标是指明被调用过程起始的指令地址,效果是将返回地址入栈,并跳转到被调用过程的起始处。

ret:从栈中弹出地址,并跳转到这个位置。

函数返回值存在%eax中

3.7.3寄存器使用惯例

程序寄存器是唯一能被所有过程共享的资源,调用者保存寄存器 和 被调用者保存寄存器是分开的,对于哪一个寄存器保存函数调用过程中的返回值要有统一的约定。

3.11使用GDB调试器

命令

参数含义

说明

display

设置自动显示列表,不带参数时显示列表中所有表达式

delete display dnums…..

自动显示列表的ID号

删除自动显示列表

disable dislay dnums…..

自动显示列表的ID号

禁用自动显示列表

enable display dnums…..

自动显示列表的ID号

使用自动显示列表

info display

显示自动显示列表中的表达式

show convenience

显示快捷变量

macro expand expression

包含宏定义的表达式

将表达式宏展示

info macro macroname

宏定义的名字

查看宏定义的信息

generatre-core file

产生转储文件

backtrace

n 最内层的n个函数栈帧

-n 最外层n个函数栈帧

栈帧回溯

frame

栈帧号或者内存地址

选定栈帧,不带参数时显示栈帧简要信息

up

栈帧号

选定栈帧上移

down

栈帧号

选定栈帧下移

info frame

显示栈帧详细信息

info agrs

显示当前选定栈帧的函数参数

info locals

显示当前选定栈帧中的所有局部变量

set variable expr

赋值表达式

给变量赋值或者修改变量的值

print

赋值表达式

给变量赋值或者修改变量的值

jump

使程序从另外的地址开始执行

signal sig

信号值或者信号和名称

向被调试程序发送信号

call expr

包含函数调用的表达式

调用函数

print expr

包含函数调用的表达式

调用函数

list

函数名 行号 地址 偏移等

列出程序源码

set listsize count

设置 list默认显示的行数

disassemble

反汇编被调试程序

set disassembly-flavor instruction-set

设置反汇编格式

 

命令

参数含义

说明

display

设置自动显示列表,不带参数时显示列表中所有表达式

delete display dnums…..

自动显示列表的ID号

删除自动显示列表

disable dislay dnums…..

自动显示列表的ID号

禁用自动显示列表

enable display dnums…..

自动显示列表的ID号

使用自动显示列表

info display

显示自动显示列表中的表达式

show convenience

显示快捷变量

macro expand expression

包含宏定义的表达式

将表达式宏展示

info macro macroname

宏定义的名字

查看宏定义的信息

generatre-core file

产生转储文件

backtrace

n 最内层的n个函数栈帧

-n 最外层n个函数栈帧

栈帧回溯

frame

栈帧号或者内存地址

选定栈帧,不带参数时显示栈帧简要信息

up

栈帧号

选定栈帧上移

down

栈帧号

选定栈帧下移

info frame

显示栈帧详细信息

info agrs

显示当前选定栈帧的函数参数

info locals

显示当前选定栈帧中的所有局部变量

set variable expr

赋值表达式

给变量赋值或者修改变量的值

print

赋值表达式

给变量赋值或者修改变量的值

jump

使程序从另外的地址开始执行

signal sig

信号值或者信号和名称

向被调试程序发送信号

call expr

包含函数调用的表达式

调用函数

print expr

包含函数调用的表达式

调用函数

list

函数名 行号 地址 偏移等

列出程序源码

set listsize count

设置 list默认显示的行数

disassemble

反汇编被调试程序

set disassembly-flavor instruction-set

设置反汇编格式

实验楼实验五

要求

使用gcc –S –o main.s main.c -m32
命令编译成汇编代码,如下代码中的数字和函数名请自行修改以防与他人雷同

int g(int x) {   return x + 3; }  int f(int x) {   return g(x); int main(void) {   return f(8) + 1; }

1.删除gcc产生代码中以"."开头的编译器指令,针对每条指令画出相应栈帧的情况
2.(选做)使用gdb的bt/frame/up/down 指令动态查看调用栈帧的情况

实验结果

2.

参考资料:

http://blog.csdn.net/21cnbao/article/details/7385161

http://blog.csdn.net/nabila/article/details/7786428

Linux(10.5-10.11)学习笔记的更多相关文章

  1. linux内核分析第四周学习笔记

    linux内核分析第四周学习笔记 标签(空格分隔): 20135328陈都 陈都 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.co ...

  2. C++11 学习笔记 std::function和bind绑定器

    C++11 学习笔记 std::function和bind绑定器 一.std::function C++中的可调用对象虽然具有比较统一操作形式(除了类成员指针之外,都是后面加括号进行调用),但定义方法 ...

  3. Linux内核分析第二周学习笔记

    linux内核分析第二周学习笔记 标签(空格分隔): 20135328陈都 陈都 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.co ...

  4. linux内核分析第一周学习笔记

    linux内核分析第一周学习笔记 标签(空格分隔): 20135328陈都 陈都 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.co ...

  5. Linux就该这么学11学习笔记

    参考链接:https://i.cnblogs.com/EditPosts.aspx?opt=1 文件传输协议 一般来讲,人们将计算机联网的首要目的就是获取资料,而文件传输是一种非常重要的获取资料的方式 ...

  6. zepto源码--核心方法10(位置)--学习笔记

    今天基本上就是zepto学习笔记的最后一篇了,介绍一下有关位置的函数,position, offset, scrollLeft, scrollTop scrollLeft 如果所选取的包装集不存在,则 ...

  7. Linux简易APR内存池学习笔记(带源码和实例)

    先给个内存池的实现代码,里面带有个应用小例子和画的流程图,方便了解运行原理,代码 GCC 编译可用.可以自己上网下APR源码,参考代码下载链接: http://pan.baidu.com/s/1hq6 ...

  8. C++11学习笔记

    C++11 1.long long新类型 2.列表初始化 int t=0; int t={0}; int t(0); int t{0}; 注意:如果我们使用列表初始化有丢失信息的风险,则编译器报错 l ...

  9. linux下文件搜索命令学习笔记

    1. locate:按照文件名搜索文件 locate filename 与find在整个操作系统中遍历搜索不同,locate命令在/var/lib/mlocate这个后台数据库中按照文件名搜索,所以优 ...

  10. Linux文件与目录管理(学习笔记)

    本笔记为<鸟哥linux私房菜>第六章学习笔记 一.目录与路径 相对路径与绝对路径 绝对路径:一定由根目录 / 写起              正确度比较好 相对路径:不是由 / 写起  ...

随机推荐

  1. 转 Android Dalvik虚拟机初识

    首先,让我们来思考下面几个问题: 什么是Dalvik虚拟机? Dalvik VM与JVM有什么区别? Dalvik VM有什么新的特点? Dalvik VM的架构是怎么样的? 首先,我得承认第一个问题 ...

  2. Effective Java 42 Use varargs judiciously

    Implementation theory The varargs facility works by first creating an array whose size is the number ...

  3. Effective Java 68 Prefer executors and tasks to threads

    Principle The general mechanism for executing tasks is the executor service. If you think in terms o ...

  4. GDI学习之俄罗斯方块

    做个玩玩 public Form1() { InitializeComponent(); } #region 定义砖块int[i,j,y,x] Tricks:i为那块砖,j为状态,y为列,x为行 pr ...

  5. 由IP和掩码计算广播地址

    public static IPAddress GetBroadcast(IPAddress ipAddress, IPAddress subnetMask) { var ip = ipAddress ...

  6. 烂泥:ubuntu中使用virt-manager图形化新建虚拟机

    本文由秀依林枫提供友情赞助,首发于烂泥行天下. 上一篇文章介绍了,如何在ubuntu下安装KVM的虚拟机管理器virt-manager,这篇文章我们来介绍,如何在图形界面下使用virt-manager ...

  7. linux进程间通信-有名管道(FIFO)

    有名管道(FIFO) 命名管道也被称为FIFO文件,是一种特殊的文件.由于linux所有的事物都可以被视为文件,所以对命名管道的使用也就变得与文件操作非常统一. (1)创建命名管道 用如下两个函数中的 ...

  8. xamarin.android 给View控件 添加数字提醒效果-BadgeView

    本文代码从java项目移植到.net项目   java开源项目:https://github.com/jgilfelt/android-viewbadger using System; using S ...

  9. Class to connect postgres with python in psycopg2

    For we need to connect the postgres db in project very frequently, so write the follows class: impor ...

  10. Python中的逗号有什么作用?

    最近研究python  遇到个逗号的问题 一直没弄明白 今天总算搞清楚了 1.逗号在参数传递中的使用: 这种情况不多说  没有什么不解的地方 就是形参或者实参传递的时候参数之间的逗号 例如def  a ...