汇编 —— 起步

作为非计算机专业的孩子,想要了解每一条C语句到底发生了什么,学习汇编也就变得水到渠成了。经过好几天的折腾,总算搞懂了一点点,一开始看王爽老师的《汇编语言 第三版》,讲得确实不错,但是8086cpu的汇编环境确实有点老,装了一个DOSBos,debug.exe倒是能用了,但是edit,masm啥的全都没有啊,更重要的是将来的工作都是在linux上进行,故而学到第四章就放弃了,转而学习linux环境的汇编。

语言

在操作的最底层,计算机处理器按照制造厂商在处理器芯片内部定义的二进制代码操作数据,预置的代码称之为指令码,不同的处理器包含不同类型的指令码。
高级语言分为编译语言(编译生成指令码,指令码生成可执行文件),解释语言(由单独的程序读取和执行,程序代码转换成指令码),混合语言(包含前两种语言的特点,比如java语言,编译生成字节码再由java虚拟机JVM解释)。

计算机结构

存储器由一些可变模式的容器组成。
晶体管开关及其支持部件合在一起称之为存储单元。
计算机中的成员:晶体管、二极管、硅、半导体、电容。
Intel的32位体系结构叫做IA-32,AMD创造的向后兼容的64位x86体系结构就做x86_64.
cpu为了完成指令让它做的事情而依赖的所有的电机制统称为CPU的微体系结构。
操作系统可以为任务列表中的每一个程序赋予一个优先级,高优先级的任务获得更多的时钟周期,低优先级的任务获得较少的时钟周期。
linux内核和图形用户界面是完全分开的,系统寄存器或被标识为内核空间,或被标识为用户空间,运行在用户空间的任何内容都不能被写入内核空间中,也不能从内核空间读取内容。只有运行在内核空间中的软件才能直接访问物理硬件。
CPU的效率取决于它一次能调集的地址线根数。

寄存器

IA-32处理器

寄存器作用
通用8个32位用于存储数据的存储器
6个16位处理内存访问的寄存器
指针32位寄存器,指向下一条指令码
浮点数据8个80位寄存器,用于浮点数学计算
控制5个32位用于确定处理器操作模式的处理器
调试8个32位包含调试信息的处理器

32位x86体系结构的8个通用寄存器:EAX, EBX, ECX, EDX, EBP, ESI, EDI, ESP.

通用寄存器作用
EAX操作数和结果数据的累加器
EBX指向数据段内存中数据的指针
ECX字符串和循环操作的计数器
EDXI/O指针
EDI字符串操作的目标的数据指针
ESI字符串操作的源的数据指针
ESP堆栈指针
EBP堆栈数据指针

通用寄存器:

这里写图片描述

半寄存器:
这里写图片描述

指针寄存器:EIP寄存器,跟踪下一条指令码。

段寄存器作用
CS代码段
DS数据段
SS堆栈段
ES附加段指针
FS附加段指针
GS附加段指针
控制寄存器描述
CR0控制操作模式和处理器状态的系统标志
CR1
CR2内存页面错误信息
CR3内存页面目录信息
CR4说明处理器特性或能力的标志

内存

RAM: 随机访问存储,不会影响其他内容,就像在图书馆检索后找书一样。
ROM: 顺序访问,依次搜索。
一旦一个内存地址被应用到地址管脚上,数据管脚就会发生变化。
一个字节(byte)由8位(bit)

名称内存单元
字节1
2
双字4
四字8
十字节10
段落16
256
65536

字单元:存放一个字型数据的内存单元,16位,由两个连续的内存单元组成。
任何两个连续的内存单元都可以看作一个字单元。
一次处理双字的计算机即32位,一次处理4字的计算机就是64位,多少位就是针对处理器来说的。
中央处理单元(CPU)从内存中独入一个字节(双字、四字等)时,它将该字节的内存地址放到他的地址管脚上,编码成二进制数,字节随后出现在数据管脚上。
每一个CPU都含有存储数据的地方,称之为寄存器。
cpu在指针寄存器的指引下行进,其工作的本质就是将不同的机器指令字节压入8个晶体管寄存器中。
数据总线上一根线对应1位(bit),地址总线上对应一个存储单元 (字节,byte)
cpu在段地址中进行读写操作就是在物理存储器中进行读写操作。
地址总线影响着内存的大小。

内存段地址偏移地址
数据段DSSI
代码段CSIP
栈段SSSP

一段内存可以同时是代码段、数据段、栈空间,也可以啥也不是。

使用gdb查看内存地址的存储值:

$ gdb exe
(gdb) start
Temporary breakpoint 1 at 0x804845c: file x.c, line 4.
Starting program: /home/edemon/workspace/exe 

Temporary breakpoint 1, main () at x.c:4
4           char *p = (char *)malloc(1);
(gdb) n
5           *p = 'a';
(gdb) p p
$1 = 0x804b008 ""
(gdb) help x
Examine memory: x/FMT ADDRESS.
ADDRESS is an expression for the memory address to examine.
FMT is a repeat count followed by a format letter and a size letter.
Format letters are o(octal), x(hex), d(decimal), u(unsigned decimal),
  t(binary), f(float), a(address), i(instruction), c(char), s(string)
  and z(hex, zero padded on the left).
Size letters are b(byte), h(halfword), w(word), g(giant, 8 bytes).
The specified number of objects of the specified size are printed
according to the format.

Defaults for format and size letters are those previously used.
Default count is 1.  Default address is following last thing printed
with this command or "print".
(gdb) x/1ub 0x804b008
0x804b008:  0
(gdb) x/1ub 0xb7fbd0a0
0xb7fbd0a0 <environ>:   12
(gdb) x/3ub 0xb7fbd0a0
0xb7fbd0a0 <environ>:   12  245 255

#在调试中查看各个寄存器的值
(gdb) info all-register
eax            0xb7fbd0a0   -1208233824
ecx            0xbffff470   -1073744784
edx            0xbffff494   -1073744748
ebx            0xb7fbb000   -1208242176
esp            0xbffff440   0xbffff440
ebp            0xbffff458   0xbffff458
esi            0x0  0
edi            0x8048350    134513488
eip            0x804845c    0x804845c <main+17>
eflags         0x282    [ SF IF ]
cs             0x73 115
ss             0x7b 123
ds             0x7b 123
es             0x7b 123
fs             0x0  0
gs             0x33 51
st0            0    (raw 0x00000000000000000000)
st1            0    (raw 0x00000000000000000000)
st2            0    (raw 0x00000000000000000000)
st3            0    (raw 0x00000000000000000000)
st4            0    (raw 0x00000000000000000000)
st5            0    (raw 0x00000000000000000000)
st6            0    (raw 0x00000000000000000000)
st7            0    (raw 0x00000000000000000000)
fctrl          0x37f    895
fstat          0x0  0
ftag           0xffff   65535
fiseg          0x0  0
---Type <return> to continue, or q <return> to quit---q
Quit

段寄存器是操作系统的工具。

汇编

汇编编程模型,实模式平面模型和保护模式平面模型的主要区别:在实模式平面模型下,自己写的程序拥有操作系统交给他的整个内存空间,在保护模式平面模型下,程序得到内存的一部分,其他仍然属于操作系统。
在实模式下计算机是开放的,保护模式下的计算机则限制了我们不能做一些事情,比如直接访问端口硬件,内存映射视频系统,直接调用BIOS。
汇编语言程序的三个组件:操作码助记符(push, mov, sub等)、数据段、命令(比如.section命令)。
考虑到移植性,很多编译器编码遵守“最小公分母”原则,所以程序的执行速度并不是最快的。
汇编语言程序一般就有三个段落:数据段(.data,声明带有初始值的数据元素),静态内存段(.bss,声明使用零值初始化的数据元素),文本段(.text)。
处理器通过地址总线、数据总线、控制总线和计算机的系统内存、输入设备、输出设备相连。

intel处理器官网:www.intel.com
反汇编(Disassembly):把目标代码转为汇编代码的过程
下面是汇编学习环境:

toolinfouse example
汇编器AS - the portable GNU assembleras -o test.o test.s
连接器ld - The GNU linkerld -o test test.o
调试器gdb - The GNU Debuggergdb a.out
编译器gcc - GNU project C and C++ compilergcc hello.c
反汇编器objdump - display information from object filesobjdump -d a.out > a.s
分析器gprof - display call graph profile datagoto tag; ^_^

分析器的三类文件:

FILES
       "a.out"
           the namelist and text space.

       "gmon.out"
           dynamic call graph and profile.

       "gmon.sum"
           summarized dynamic call graph and profile.

tag:
分析器的使用如下:

edemon@ubuntu1:~/workspace$ gcc hello.c -pg -o hello -O2 -lc
edemon@ubuntu1:~/workspace$ ./hello
hello
edemon@ubuntu1:~/workspace$ ls |grep gmon
gmon.out
edemon@ubuntu1:~/workspace$ gprof hello gmon.out -p

Flat profile:

Each sample counts as 0.01 seconds.
 no time accumulated

  %   cumulative   self              self     total           
 time   seconds   seconds    calls  Ts/call  Ts/call  name    

 %         the percentage of the total running time of the
time       program used by this function.

cumulative a running sum of the number of seconds accounted
 seconds   for by this function and those listed above it.

 self      the number of seconds accounted for by this
seconds    function alone.  This is the major sort for this
           listing.
...
...

GNU连接器ld查找的是_start来确定程序开始的位置,但是gcc查找的是main标签,所以我们需要修改:
所以如果是使用gcc汇编和连接汇编程序,那么将_start改成main即可。
调试汇编程序,as的调试选项[--gstabs+] [--gdwarf-2] [--gdwarf-sections]
例如:
as -gstabs -o test.o test.s
gdb中使用print打印2进制、10进制、16进制的格式:print/t, print/d, print/x
系统:Linux ubuntu1 3.19.0-74-generic #82-Ubuntu SMP Thu Oct 20 21:46:04 UTC 2016 i686 i686 i686 GNU/Linux
标准的C动态库文件:/lib/i386-linux-gnu/libc.so.6

Intel和AT&T的区别:
AT&T使用$表示立即操作数,Intel不需要。
AT&T在寄存器名称前使用&,Intel不需要。
AT&T的source、destination的顺序和Intel是相反的,比如AT&T的mov: movx source, destination, Intel的mov:mov desctination, source
AT&T在助记符后面使用单独的字符表示数据长度,而Intel使用单独的操作数表示长度。
定义段和偏移值,AT&T: ljmp $section,$offset, Intel使用 jmp section:offset

第一个程序

和高级语言不同的是,在汇编中写一个“hello world”不再是一件容易的事情。我的第一个汇编程序是简单的寄存器存值(够简单吧)。
内容:

.section .text
.global main
main:
movl $100, %eax
int $0x80

int $0x80是一个Linux系统调用,从内核访问控制台显示。
用gdb执行并查看寄存器的值

[edemon@CentOS asm]$ gcc -gdwarf-2 -o mov mov.s
[edemon@CentOS asm]$ gdb mov
GNU gdb (GDB) Red Hat Enterprise Linux (7.2-90.el6)
...
Starting program: /home/edemon/workspace/asm/mov 

Temporary breakpoint 1, main () at mov.s:4
4   movl $100, %eax
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.192.el6.i686
(gdb) n
5   int $0x80
(gdb) info register
eax            0x64 100
ecx            0xeb17dccc   -350757684
edx            0x1  1
ebx            0x3a3ff4 3817460
esp            0xbffff22c   0xbffff22c
ebp            0xbffff2a8   0xbffff2a8
esi            0x0  0
edi            0x0  0
eip            0x80483f1    0x80483f1 <main+5>
eflags         0x200246 [ PF ZF IF ID ]
cs             0x73 115
ss             0x7b 123
ds             0x7b 123
es             0x7b 123
fs             0x0  0
gs             0x33 51
(gdb) n
0x080483f3 in main ()

可以发现eax已经变成100.


hello world汇编:
两天之后,我发现linux下的AT&T汇编hello world原来也挺简单的 (多亏能调用C的函数)。哈哈哈,总算入门了。(16.12.20)

.section .data
output:
    .asciz "hello world\n"
.section .text
.globl main
main:
    pushl $output
    call printf
    call exit

编译执行:

[edemon@CentOS workspace]$ gcc cmov.s
[edemon@CentOS workspace]$ ./a.out 
hello world
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值