发表于 2024/03/27 11:10:58 [计算机基础] 浏览次数:273
# .data段 包含了已经初始化的数据项的数据定义,已经初始化的数据在程序开始运行前就拥有了自己的值。这些值是可执行文件的一部分
# 当可执行文件被加载到内存中用于执行时,它们被加载到内存中。 定义的初始数据项越多,可执行文件就越大,需要更长的时间从磁盘加载到内存
.code32
.data
msg: # 变量名 代表变量值的地址
.ascii "hello" # 变量的值 字符串(h是最低有效元素,小端序存放结果为hello)
len = . - msg
snippet:
.ascii "KANGAROO"
x:
.int 0x12345678 # 数字类型 1是最高有效位,小端序存放结果为78 56 34 12(4个字节)
# .bss段,当程序需要从磁盘上读取文件数据时,读取的数据需要一个缓冲区来存放,这样的缓冲区就是在.bss段中定义的。
# .bss段中定义数据项不会添加到可执行文件的大小中。
#.bss
# 真正组成程序的机器指令存放在.text段中,一般情况下,.text段中不进行数据项的定义
.text
.global _start
_start:
#1、 mov指令:复制,l:双字 4字节 w:字 2字节 b:单字节
# movw $0x67fe,%ax # 立即数0x67fe存入ax中
# movw %ax,%bx # ax的数存入bx中-
# movb %bh,%cl # bx高8位67存入cx的低8位中
# movb %bl,%ch # bx的低8位fe存入cx高8位中,cx的值:0xfe67
# xchgb %cl,%ch #交换两个寄存器的值,cx的值:0x67fe
# movl (msg),%eax #将变量中的内容放到寄存器中,从内存读始终是从低位开始读,寄存器右边低位左边高位,所以结果是:0x6c6c6568(lleh)
# movb (msg),%al # 将内容存入al(ax低八位)中,将
# movl (x),%eax # 值 0x12345678×(内存从低位开始读,先读78再读56...,寄存器右边低位左边高位,从右往作存78,56...)
# movw (x),%dx # dx寄存器两个字节,结果为0x5678
#2、 加减指令
# # inc指令:加1(一个操作数)
# # dec指令: 减1(一个操作数)
# movl $0xFFFFFFFF,%eax
# movl $0x2D,%ebx
# dec %ebx # 结果0x2C
# inc %eax # 结果 0x0
# movl $0x5,%eax # 设置eax的值为5
# DoMore:dec %eax # 减1 DoMore:是一个标号
# jnz DoMore # 跳转到DoMore(如果eax的值不为0,当eax的值是0时,eflags寄存器的第6位(ZF,从右往左0开始),将会设置为1代表操作数为0了)
# # jnz指令每次循环都会判断ZF位
#
#3、 字符串转小写
# movl $snippet,%ebx # 将字符串的地址(也是首字母的地址)放到ebx中
# movl $0x8,%eax # 循环次数8
# DoMore2:addb $0x20,(%ebx) # 将地址中的字符(1个字节b)加32(十进制),变为小写字母
# inc %ebx # 地址加1(指向下一个字符)
# dec %eax # 减1 直到eax为0(循环8次)
# jnz DoMore2 # 循环操作 最有snippet的所有字符变为小写
# movl (snippet),%ebx # 将字符串(前4个字节)放到ebx中 结果 0x676e616b (gnak)
#4、负数补碼表示
# movl $0x5,%eax # 将0x5放入eax (有符号数:最高位(最左边)为1表示负数,为0表示正数)
# DoMore3:dec %eax # 递减
# # jmp DoMore3 # 跳转 循环(注释掉,以免再次死循环) ,当eax减到-1时,为0xFFFFFFFF(负数的补碼。负数补碼:原码取反+1, 补码->原碼:减1取反)
# # cpu在晶体管逻辑层面上,并不真正需要减法,它只产生减数的补碼,并将其与被减数相加
# # 如:3-2 = 3+(-2); -2以补碼的形式存放,直接按位相加即可。
#5、正数转负数
# #neg指令 将一个数取负数(补碼形式)
# movl $0xF,%eax # 0xF 16
# neg %eax # 取负数 0xFFFFFFF1(-16的补碼)
# addl $0xF,%eax # 0
#6、带符号移动(复制)
# movw $0xFFD6,%ax # -42放到ax(2个字节)中
# movl %eax,%ebx # ebx(4字节) 还是 0x0000FFD6 (但表示的值是65494,原来的符号位变成了普通位)
#
# # movsx指令:带符号一起移动
# mov $0xFFD6,%ax
# movsx %ax,%ebx # ebx (4字节) 0xFFFFFFD6(-42)
#
#7、 乘法
# # mul:乘法(无符号) div:除法(无符号)
# # imul:乘法(有符号) idiv:除法(有符号)
# movl $447,%eax
# movl $1739,%ebx
# mul %ebx # 乘法,显式因子(r/m8(16,32) 任意8位,16位,32为的寄存器或内存地址,不能是立即数),隐式因子(al,ax,eax 根据显式因子的位数而定)
# # 结果存放在eax中 777333, 并且edx为0(edx用于保存乘法运算的部分结果)同时eflags寄存器的进位标志位CF(第0位)是0,表示无进位
#
#8、乘法 进位
# # 将数设大一点
# movl $0xFFFFFFFF,%eax
# movl $0x3B72,%ebx
# mul %ebx # 计算结果 eax:0xffffc48e edx:0x3b71(进位后高位部分) eflags CF位设置位1(有进位)
#9、 除法
# movl $0x8,%eax # 隐式操作数 被除数(商的整数部分 al,ax,eax 对应的余数部分ah,dx,edx)
# movl $0x3,%ebx # 显式操作数 除数(r/m8(16,32) )
# div %ebx # 结果 商为2保存在eax中,余数2保存在edx中
#10、push指令(将16位或32寄存器或内存值压入堆栈,64位linux编译不过,在代码顶部加上.code32) (其他push指令:pushf pushfd pusha pushad)
# movl $0xaabbffee,%eax
# pushl %eax # 将esp的值(栈顶元素的地址)减小4(堆栈增长方向从高到低,eax占4个字节),将eax寄存器中的数据压入堆栈(压入顺序:aa bb ff ee)
#pushw %ax # 将esp减小2(ax占2个字节),将ax的值压栈
# pop指令(弹栈,弹出的字节数由操作数决定,只能是16位或32位)(其他pop指令:popa,popad,popf,popfd)
# popw %bx # 取出栈顶的2个字节(bx的大小是2个字节)放到bx中 取出顺序 ee ff (存入bx结果: ffee ,从右往左存)
#11、系统调用 (控制台输出hello)
#Linux的系统调用通过int 80h实现,用系统调用号来区分入口函数。 操作系统实现系统调用的基本过程是:
#应用程序调用库函数(API);
#API将系统调用号存入EAX,然后通过中断调用使系统进入内核态;
#内核中的中断处理函数根据系统调用号,调用对应的内核函数(系统调用);
#系统调用完成相应功能,将返回值存入EAX,返回到中断处理函数;
#中断处理函数返回到API中;
#API将EAX返回给应用程序。
# movl $len, %edx #参数三 字符串长度 (edx)
# movl $msg, %ecx #参数二 要显示的字符串(ecx)
# movl $1, %ebx #参数一 文件描述符(1:标准输出 ebx)
# movl $4, %eax #系统调用号(sys_write eax)
# int $0x80 #调用内核功能 int0x80指令首先把它后面的那条指令地址压入栈顶(记录系统调用后的返回地址),系统调用完成后再用IRET指令弹出继续执行
# #退出程序
# movl $0, %ebx #参数一 退出代码(ebx)
# movl $1, %eax #系统调用号(sys_exit eax)
# int $0x80 #调用内核功能
#12、位
#and 与操作符 可以用来屏蔽一些不需要的位
#movl $0xffffffff,%eax
#movl $0x0000ffff,%ebx
#andl %ebx, %eax # 与运算 结果存放到目标操作数eax中
# or 或操作
#movl $0xffffffff,%eax
#movl $0x0000ffff,%ebx
#orl %ebx, %eax # 结果存放到目标操作数eax中
# xor 异或操作 可以用来清零(一个数与自身异或结果为0)
#movl $0xffee00ff,%eax
#xorl %eax, %eax # 结果为0 存放到目标操作数eax中
# not 非操作 取反
#movl $0xffffff00,%eax
#notl %eax # 结果为0xff
# shl 左移操作
#movl $0xffffffff,%eax
#shll $0x4,%eax # 左移4位 结果为0xfffffff0
# shr 右移操作
movl $0xfffffff0,%eax
shrl $0x4,%eax # 左移4位 结果为0x0fffffff