Linux汇编-回忆录一

===汇编基础====
汇编语言程序由定义好的段构成,常用三个段:
数据段  初始值的数据元素
BSS段   使用零初始化的数据元素
文本段  程序代码

注明:
在BSS段中声明的数据,是不包含在可执行程序中的,但是
数据段必然包含在科执行程序中

汇编的编写有如下规则:
定义段      使用.section伪指令定义)
定义入口点  使用.globl伪指令定义,用于标明程序从哪个
            开始执行程序,一般默认为.global _start
            如果是GCC编译,定义为.globl main

====汇编伪指令====
.section    标明使用哪种类型的程序段
.data       标明是数据段
.text       标明是代码段
.globl      标明程序的入口点
.equ        定义静态符号,一般在文本段引用(使用$符号引用)
.comm       声明为初始化的数据的通用内存区域
.lcomm      声明为初始化的数据的本地内存区域

伪指令.comm, .lcomm两者格式均类似".comm symbol, length"

====数据类型指令====
.long   long整型
.byte   字节值
.int    整型
.ascii  字符串
.asciz  以空字符结尾的字符串
.double 双精度浮点数
.float  单精度浮点数
.octa   16字节整数
.quad   8字节整数
.short  16位整数

====汇编栈帧====
汇编语言使用标签标明地址,例子如下
label_name:
    assemble code
    ...

栈有个术语需要熟悉。一个是栈底,栈底表示栈的起始位置,位于高
地址;另一个是栈顶,栈顶表示栈的当前使用位置,位于低地址,数据不断的
入栈,出栈,使得栈顶一直处于活动状态;另外需要知道的是栈的增长是向低
地址方面

标准制定,%esp寄存器保存栈顶指针,%ebp寄存器保存栈底指针,这两个寄存器只能
用于这样的用途,用于其他用途都是不太明智的做法

====寻址方式====
直接寻址模式
exp: movl ADDRESS, %eax

变址寻址方式
exp: movl address_start(,%ecx,1), %eax

间接寻址模式
exp: movl (%eax), %ebx
     # %ebx的值是一个地址

基址寻址模式
exp: movl 4(%eax), %ebx

立即数寻址
exp: movl $12, %eax

寄存器寻址
exp: movl %eax, %ebx

寻址方式可以概要表示为如下公式:
ADDRESS_OR_OFFSET(%BASE_OR_OFFSET,%INDEX,MULTIPLIER)
FINAL ADDRESS = ADDRESS_OR_OFFSET + %BASE_OR_OFFSET + MULTIPLIER * %INDEX
说明:
1.ADDRESS_OR_OFFSET和MULTIPLIER必须是常量
2.其余两个必须是寄存器,如果某一个值为空,留空就行

====汇编指令====
此处并未全部列出,列出自己所学所知

1.cmpl指令比较两个数,并设置%eflags寄存器的值,然后供下面的跳转指令使用
比较指令格式cm operand1, operand2,注意操作数的位置,尤其是和INTEL的
语法不一致

2.条件跳转指令
je  相等
jg  第二个数大于第一个数
jge 第二个数大于等于第一个数
jl  第二个数小于第一个数
jle 第二个数小于等于第一个数
jmp 无条件跳转

3.cpuid的指令使用单一寄存器%eax作为输入,返回的是一个字符串,地址从
低到高存储在%ebx, %ecx, %edx
%eax的值
0   厂商ID字符串
1   处理器类型
2   处理器缓存配置
3   处理器序列号
4   缓存配置
5   监视信息

====跳转分支====
跳转    汇编语言必须使用跳转实现很多功能
        使用单一指令jmp location(一般是标签地址)
调用    使用call指令
中断    软中断+硬中断
        exp1: int 0x80属于软中断
        exp2: 硬件出现被除数为零中断程序属于硬中断

条件跳转
1.近跳转    16或32地址偏移
2.短跳转    8位地址偏移
3.不支持内存模式远跳转

====汇编函数====
1.定义方式
.type function_name, @function
function_name:
    function_code
    …

2.调用汇编函数
call function_name256

===命令行参数传递====
Linux程序启动的时候,命令行参数传递的栈帧结构如下
高地址  环境变量
        命令行参数
        指向环境变量的指针
分割    0x00000000
        指向命令行参数N的指针
        ...
        指向命令行参数2的指针
        指向命令行参数1的指针
        程序名称
        参数数目
        ...
说明:参数数目永远不为0,大于等于1,因为程序名称总是存在

===系统调用===
linux内核系统调用
调用号存在vim /usr/include/asm/unistd.h

系统调用规定的输入值方式
%eax    系统调用号
%ebx    第一个参数
%ecx    第二个参数  
%edx    第三个参数
%esi    第四个参数
%edi    第五个参数

如果超过6个参数,那么%ebx保存指向输入参数的内存位置指针,那么参数
内存要求存储连续性,系统调用的返回值是存储在%eax寄存器中

内联汇编使用asm(“asm code”)的方式嵌入,它可以自由嵌入汇编代码,不过
不能使用C代码中的局部变量,只能使用全局变量

时间: 2024-10-04 17:49:21

Linux汇编-回忆录一的相关文章

Linux 汇编

Linux 汇编语法格式 绝大多数 Linux 程序员以前只接触过DOS/Windows 下的汇编语言,这些汇编代码都是 Intel 风格的.但在 Unix 和 Linux 系统中,更多采用的还是 AT&T 格式,两者在语法格式上有着很大的不同: 在 AT&T 汇编格式中,寄存器名要加上 '%' 作为前缀:而在 Intel 汇编格式中,寄存器名不需要加前缀.例如: AT&T 格式 Intel 格式 pushl %eax push eax 在 AT&T 汇编格式中,用 '$'

Linux汇编与C互相调用

一.简介 C语言调用汇编有两种方式:1.通过内嵌汇编  2.通过编译链接. 二.基础知识 对于C和汇编语言的接口主要有两个问题需要解决 1.调用者与被调用者的参数传递 正常的,定义一个函数总是希望它完成某些功能,一个毫无用处的函数将毫无意义.这些功能有常常是更大的功能的一部分,而函数完成这些功能或多或少都要与外界联系(一个完全不与外界联系的函数也是一个毫无意义的函数)(延时函数也要消耗时间,时间也属于外界的一种资源),比如要传递一些数据给其处理,处理过后返回处理的结果.这种数据的传递可以形象的通

Linux汇编教程01: 基本知识

在我们开始学习Linux汇编之前,需要简单的了解一下计算机的体系结构.我们不需要特别深入的了解,理解了一些基本概念对与我们理解程序会很有帮助.现在计算机的结构体系都是采用冯诺依曼体系结构的基础上发展过来的.而冯诺依曼的体系有两个主要组成部分:CPU和内存.而我们的汇编语言和这两个部分十分密切. 1.1 内存结构 内存的结构就像一排连续的房子,或者是一种矩阵.每个空间的大小是固定的,且每一个存储单元都有自己的地址或者编号.房子的地址是门牌号,而内存的每个单元都有自己的地址. 计算机的内存有数以万计

Linux汇编GAS调用C语言函数实例

Blum的书上只讲了C语言调用汇编,没讲汇编调用C语言.我自己尝试了下. 最终试验成功了,在此写出与大家分享.期间历经无数错误,无数异常,我不是醉了,而是跪了...好在最后好了. 程序实现一个换值功能,在main.s里定义a=10,b=20,然后调用C语言函数把a,b换值. 新建两个文件分别为main.s的汇编文件,还有pro.c的C语言函数文件. main.s的代码如下: .section .data a: .int 10 b: .int 20 .section .text .globl ma

Linux汇编实例讲解(一)

我们使用的平台是Linux系统,具体为CentOS-64位版.下面是第一个汇编程序的源码: # 目的:退出Linux内核并返回一个简单的状态码 # # 输入:无 # # 输出:控制台上没有输出,可以用echo $?来查看状态码 # # 变量: # %eax 保存系统调用号 # %ebx 保存返回状态 # .section .data .section .text .globl _start _start: movl $1, %eax #这是用于退出程序的Linux内核命令号(系统调用) movl

Linux汇编教程02:编写第一个汇编程序

学习一门语言,最好的方式就是在运用中学习,那么在这一章节中,我们开始编写我们的第一个汇编程序.当然作为第一个程序,其实十分的简单,但可以给大家一个基本的轮廓,了解汇编大概是这样的. 我们这个程序实际上没什么作用,只是简单的推出而已.下面就是程序的范例 # 目的: 退出程序并向Linux内核返回一个状态码 # 输入: 无 # 输出: 返回一个状态码.在程序运行结束后可以通过 echo $? 来读取状态码 # 变量: %eax保存系统调用号 %ebx保存返回状态 .section .data .se

Linux编程-回忆录二

====文件IO====Linux系统IO操作都是使用文件描述符来代表打开的文件,一个非负的的整数,它被用来指所有类型的打开的文件,包括管道,FIFO,网络套接字,终端,设备和一般文件.每个进程都有自己的一套文件描述符 经常使用的三个文件描述符是:标准输入(stdin,  STDIN_FILENO,  0)标准输出(stdout, STDOUT_FILENO, 1)标准错误(stderr, STDERR_FILENO, 2) #include <sys/stat.h>#include <

Linux编程-回忆录一

====系统调用====是应用程序和系统内核之间的API接口是系统内核对外提供的一系列功能服务系统调用的基本要点:    a.CPU从用户模式切换到内核模式    b.系统调用被优化了下,使用的是函数名称,而非调用数字号    c.系统调用可以从用户模式传递参数到内核模式,反之亦然如果想要通过函数调用号使用系统调用,可以看看syscall函数的说明系统调用看起来跟使用C函数差不多,使用函数名称来使用的系统调用实际它的步骤比较多:1.使用函数名的调用,实际是C语言库里面的wrapper函数2.传递

linux 汇编函数调用

edi第一个参数 esi第二个参数 edx第三个参数 rax保存结果 C++代码如下: char* demo(char* a,int b){ static char* buf=0; if(!buf)buf=new char[1024]; return buf;}int main(){char* tmp=0;tmp++;tmp=demo(0,1);return 0;} 汇编代码如下: