从一个简单的汇编程序学习linux下的系统调用机制
本篇原创作者:Rj45
上节 从一个简单的汇编程序学习汇编程序的结构以及编译链接的过程
中,打印hello world的汇编程序的详细解释为:
global _start
section .data
msg db "hello,world",0xa ;设置要输出的字符
len equ $ - msg ;$代表当前行的内存地址,$ - msg 代表msg的长度
section .text
_start: ;链接器从这里开始执行
mov eax,4 ;write 调用号
mov ebx,1 ;stdout =>1
mov ecx,msg ;msg的内容
mov edx,len ;msg的长度
int 0x80 ;write(1,msg,len)
mov eax,1 ;exit的调用号
mov ebx,0 ;exit(0)
int 0x80
在这个hello world的汇编代码中,可以看到,其中关键之处在于:一、 write(1,msg,len)
和 exit(0)
二、 int0x80
那么,什么是调用号,以及 int0x80
是什么意思呢?
系统调用-实现应用与内核的隔离
1、什么是系统调用?
这部分内容可参考【Linux编程】中的一篇文章--《Linux架构》:https://mp.weixin.qq.com/s/xpCLPfotCqWZ_PDagK0ERA
这是一张Linux的架构图:
最内层为硬件、 最外层为用户常用的应用、 硬件之上为内核,内核为一段计算机程序,直接管理硬件,所有计算机操作都要通过内核传递给硬件、 内核之上为系统调用,为方便调用内核,Linux将内核功能接口制作为系统调用(system call),其类似C语言中的函数,可在程序中直接调用,也即 write(1,msg,len)
和 exit(0)
。Linux系统有两百多个系统调用,其对应着不同的系统调用号、 在系统调用之上为库函数和shell,由于系统调用提供的功能非常基础,使用起来需要多个组合,故将一些常用或者特殊等功能的多个系统调用相组合就形成了库函数、 而对于shell,其为一个特殊的应用,叫命令解释器,shell通过系统调用直接调用内核。
2、如何查询系统调用号?32位Linux系统调用号:
/usr/include/x86_64-linux-gnu/asm/unistd_32.h
64位Linux系统调用号:
/usr/include/x86_64-linux-gnu/asm/unistd_64.h
系统中断-操控内核的关键
1、什么是系统中断?任何CPU在检测到从外部发来或内部产生的中断信息的时候,都需要立即处理所接受到的信息,而CPU在不再接着向下执行刚才的指令,转而去处理中断信息的过程就叫中断。中断有内中断和外中断之分。内中断又有以下几种情况:
除法错误
单步执行
执行into指令
执行int指令
2、 int0x80
是什么?
在CPU设计之初,中断信息中包含有标识中断源的类型码。中断类型码的作用是用来定位中断处理程序的。执行int指令, intn
的n为中断类型码,其功能为引发中断过程。
int0x80
,即中断号为0x80,其是上层应用程序与内核进行交互通信的唯一接口。0x80与系统调用(system_call)绑定,通过 int0x80
即可调用内核。
以下为linux0.11内核源代码中于kernel/sched.c里面的内容:
linux0.11内核源代码(https://github.com/loveveryday/linux0.11/blob/master/kernel/sched.c)
系统调用和系统中断的组合-汇编程序的实现
那么如何通过汇编程序将系统调用和系统中断结合实现目的功能呢?
以下为一个汇编程序的实现:
global _start
section .data
msg db "please enter something: "
msglen equ $-msg
display db "you have enter:"
displaylen equ $-display
section .bss
num resb 5
section .text
_start:
mov eax, 4 ;write(1,msg,msglen)
mov ebx,1
mov ecx,msg
mov edx,msglen
int 0x80
mov eax, 3 ;read(0,num,5)
mov ebx, 0
mov ecx, num
mov edx, 5
int 0x80
mov eax, 4 ;write(1,dispaly,displaylen)
mov ebx,1
mov ecx,display
mov edx,displaylen
int 0x80
mov eax, 4
mov ebx,1
mov ecx,num
mov edx,5
int 0x80
mov eax,1 ;exit(0)
mov ebx,0
int 0x80
汇编程序的框架: 设定入口、bss、data、text, 设计汇编指令代码 设置系统调用号和系统中断号
- ObjectDataSource与GridView配合使用经验总结系列一:数据绑定
- ObjectDataSource与GridView配合使用经验总结系列二:分页
- 网页优化系列二:使用Cache缓存静态文件、图片(asp.net版)
- Linux用户与“最小权限”原则
- WPF一步一脚印系列(1):万事起头难
- 自定义迭代器使用foreach
- 理解cookie的path和domain属性
- 静态页面设置缓存、动态页面设缓存(不断更新中。。。。)
- 区块链技术如何把你的游戏资产真正变为你的资产
- Python标准库07 信号 (signal包,部分os包)
- 当css属性width设为100%时
- GridView实战一:自定义分页、排序、修改、插入、删除
- Windows下程序打包发布时的小技巧
- Linux的“壳”
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 将UTC(字符串包含TZ的时间)时间转换成本地时间 python
- centos7安装telnet服务
- linux vim编辑器之环境设置
- JAVA实现UTC时间转换成北京时间
- JDK8 LocalDateTime转换成时间戳
- Grafana创建zabbix自定义template(模板)
- 一条SQL引发的“血案”:
- Grafana安装配置Elasticsearch插件
- Elasticsearch升级踩坑记之使用snapshot备份数据
- RabbitMQ的安装及集群搭建方法
- CentOs7搭建rabbitmq集群
- Rabbitmq haproxy keepalived ACCESS_REFUSED - Login was refused using authentication mechanism PLAIN.
- IDEA maven+spring mvc简单项目
- 程序员用python给了女友一个七夕惊喜!
- 微信小程序开发实战(21):发起HTTPS请求