周子轩原创作品转载请注明出处  《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用

方法一:使用API在屏幕上显示“hello world”

这个其实也是C语言经典的入门程序,源代码如下

  1. #include "stdio.h"
  2. #include "string.h"
  3. int main()
  4. {
  5. char* msg = "Hello World";
  6. printf("%s", msg);
  7. return 0;
  8. }

在实验楼中,打开此次实验链接(http://www.shiyanlou.com/courses/running/731),双击Xfce终端,cd Code目录下,gedit helloworld.c,新建并打开helloworld.c文件,在其中输入上面的代码,保存退出;

然后使用下面的指令编译链接程序:

 
gcc -o helloworld helloworld.c -m32   

接着,运行编译好的程序,

./helloworld

效果如下:

方法二:使用C内嵌汇编代码在屏幕上输出helloworld

Linux中内嵌汇编代码的语法,视频中有详细介绍,这里略去,直接给出代码和注释如下:

  1. int main()
  2. {
  3. char* msg = "Hello World";
  4. int len = 11;
  5. int result = 0;
  6. __asm__ __volatile__("movl %2, %%edx;\n\r" /*传入参数:要显示的字符串长度*/
  7. "movl %1, %%ecx;\n\r" /*传入参赛:文件描述符(stdout)*/
  8. "movl $1, %%ebx;\n\r" /*传入参数:要显示的字符串*/
  9. "movl $4, %%eax;\n\r" /*系统调用号:4 sys_write*/
  10. "int  $0x80" /*触发系统调用中断*/
  11. :"=m"(result) /*输出部分:本例并未使用*/
  12. :"m"(msg),"r"(len)  /*输入部分:绑定字符串和字符串长度变量*/
  13. :"%eax");
  14. return 0;
  15. }

使用gedit helloworld_asm.c新建文件,并输入上面的代码,使用下面的命令编译

gcc -o helloworld_asm helloworld_asm.c -m32

使用下面的命令运行

./helloworld_asm

运行效果如下

总结

即便是最简单的程序,也难免要用到诸如输入、输出以及退出等操作,而要进行这些操作则需要调用操作系统所提供的服务,也就是系统调用。除非你的程序只完成加减乘除等数学运算,否则将很难避免使用系统调用。在 Linux 平台下有两种方式来使用系统调用:利用封装后的 C 库(libc)或者通过汇编直接调用。
Linux 下的系统调用是通过中断(int 0x80)来实现的。在执行 int 80 指令时,寄存器 eax 中存放的是系统调用的功能号,而传给系统调用的参数则必须按顺序放到寄存器 ebx,ecx,edx,esi,edi 中,当系统调用完成之后,返回值可以在寄存器 eax 中获得。
所有的系统调用功能号都可以在文件 /usr/include/bits/syscall.h 中找到,为了便于使用,它们是用 SYS_<name> 这样的宏来定义的,如 SYS_write、SYS_exit 等。例如,经常用到的 write 函数是如下定义的:
ssize_t write(int fd, const void *buf, size_t count);
该函数的功能最终是通过 SYS_write 这一系统调用来实现的。根据上面的约定,参数 fb、buf 和 count 分别存在寄存器 ebx、ecx 和 edx 中,而系统调用号 SYS_write 则放在寄存器 eax 中,当 int 0x80 指令执行完毕后,返回值可以从寄存器 eax 中获得。
或许你已经发现,在进行系统调用时至多只有 5 个寄存器能够用来保存参数,难道所有系统调用的参数个数都不超过 5 吗?当然不是,例如 mmap 函数就有 6 个参数,这些参数最后都需要传递给系统调用 SYS_mmap:
void  *  mmap(void *start, size_t length, int prot , int flags, int fd, off_t offset);
当一个系统调用所需的参数个数大于 5 时,执行int 0x80 指令时仍需将系统调用功能号保存在寄存器 eax 中,所不同的只是全部参数应该依次放在一块连续的内存区域里,同时在寄存器 ebx 中保存指向该内存区域的指针。系统调用完成之后,返回值仍将保存在寄存器 eax 中。
由于只是需要一块连续的内存区域来保存系统调用的参数,因此完全可以像普通的函数调用一样使用栈(stack)来传递系统调用所需的参数。但要注意一点,Linux 采用的是 C 语言的调用模式,这就意味着所有参数必须以相反的顺序进栈,即最后一个参数先入栈,而第一个参数则最后入栈。如果采用栈来传递系统调用所需的参数,在执行int 0x80 指令时还应该将栈指针的当前值复制到寄存器 ebx中。

Linux内核分析4的更多相关文章

  1. linux内核分析作业8:理解进程调度时机跟踪分析进程调度与进程切换的过程

    1. 实验目的 选择一个系统调用(13号系统调用time除外),系统调用列表,使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用 分析汇编代码调用系统调用的工作过程,特别是参数的传递的方 ...

  2. Linux内核分析作业7:Linux内核如何装载和启动一个可执行程序

            1.可执行文件的格式 在 Linux 平台下主要有以下三种可执行文件格式: 1.a.out(assembler and link editor output 汇编器和链接编辑器的输出) ...

  3. linux内核分析作业6:分析Linux内核创建一个新进程的过程

    task_struct结构: struct task_struct {   volatile long state;进程状态  void *stack; 堆栈  pid_t pid; 进程标识符  u ...

  4. linux内核分析作业5:分析system_call中断处理过程

    1.增加 Menu 内核命令行 调试系统调用. 步骤:删除menu git clone        (tab) make rootfs 这就是我们将 fork 函数写入 Menu 系统内核后的效果, ...

  5. linux内核分析作业:以一简单C程序为例,分析汇编代码理解计算机如何工作

    一.实验 使用gcc –S –o main.s main.c -m32 命令编译成汇编代码,如下代码中的数字请自行修改以防与他人雷同 int g(int x) { return x + 3; } in ...

  6. linux内核分析作业:操作系统是如何工作的进行:完成一个简单的时间片轮转多道程序内核代码

    计算机如何工作 三个法宝:存储程序计算机.函数调用堆栈.中断机制. 堆栈 函数调用框架 传递参数 保存返回地址 提供局部变量空间 堆栈相关的寄存器 Esp 堆栈指针  (stack pointer) ...

  7. linux内核分析作业3:跟踪分析Linux内核的启动过程

    内核源码目录 1. arch:录下x86重点关注 2. init:目录下main.c中的start_kernel是启动内核的起点 3. ipc:进程间通信的目录 实验 使用实验楼的虚拟机打开shell ...

  8. linux内核分析作业4:使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用

    系统调用:库函数封装了系统调用,通过库函数和系统调用打交道 用户态:低级别执行状态,代码的掌控范围会受到限制. 内核态:高执行级别,代码可移植性特权指令,访问任意物理地址 为什么划分级别:如果全部特权 ...

  9. 《Linux内核分析》期末总结

    Linux内核设计期中总结 版权声明:本文为博主原创文章,未经博主允许不得转载. 前八周博客汇总及总结 Linux内核设计第一周——从汇编语言出发理解计算机工作原理 我们学习了汇编语言的基础知识,这一 ...

  10. 《Linux及安全》期中总结&《Linux内核分析》期终总结

    [5216 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000] WEEK NINE ...

随机推荐

  1. 【TCP_协议_socket接口】-jmeter

    1.ip 2.端口号 3.传入参数 4.告诉软件返回  最后以为是什么,不然就会报错 或者无限制的等待  查ascll 码表 启动接口的方法

  2. 如何在DCS管理控制台将两个Redis主备实例建立全球灾备。

    华为云分布式缓存服务DCS,具有强大的功能,现在小编教大家如何在DCS管理控制台将两个Redis主备实例建立全球灾备. 建立全球灾备,会对主实例和备实例进行升级,实例进程会重启,连接会中断.同时备实例 ...

  3. mongodb windows 4 zip安装

    安装mongoDB目的:学习Express,顺带mongodb. 本文目的: 4.0.2的mongodb在windows7上竟然安装不了. 没办法,用压缩包手动安装吧... 安装环境:win7sp1x ...

  4. PowerDesigne 建立概念数据模型

    本文主要介绍PowerDesigner概念数据模型以及实体.属性创建. 一.新建概念数据模型1)选择File-->New,弹出如图所示对话框,选择CDM模型(即概念数据模型)建立模型. 2)完成 ...

  5. spring-boot-mybatis搭建

    写在开始 mybatis是一个持久化框架,支持手动sql.存储过程.高级映射.mybatis支持XML方式或注解方式将POJO与数据库表间建立映射. maven依赖 spring-boot.mysql ...

  6. 后端编程语言PHP

    | 版权声明:本文为博主原创文章,未经博主允许不得转载. 一.PHP 简介 PHP 是一种创建动态交互性站点的强有力的服务器端脚本语言. PHP 脚本在服务器上执行. 什么是 PHP?(超文本预处理器 ...

  7. Beta周第8次Scrum会议(11/17)【王者荣耀交流协会】

    一.小组信息 队名:王者荣耀交流协会 小组成员 队长:高远博 成员:王超,袁玥,任思佳,王磊,王玉玲,冉华 小组照片 今天拍照的人是王磊.因此他没有出现在照片中. 二.开会信息 时间:2017/11/ ...

  8. 解释Spring中IOC, DI, AOP

    oc就是控制翻转或是依赖注入.通俗的讲就是如果在什么地方需要一个对象,你自己不用去通过new 生成你需要的对象,而是通过spring的bean工厂为你长生这样一个对象.aop就是面向切面的编程.比如说 ...

  9. 2nd 简单四则运算更新

    简单四则运算更新 功能:由随机数决定出题为10个以内的数字,并确定是否出现括号(仅限一对),顺序输出表达式,并用栈的方式进行计算,判断正误.其他功能有待进一步实现. 头文件 #include < ...

  10. Windows搭建Log4Net+FileBeat+ELK日志分析系统过程

    参考博客:http://udn.yyuap.com/thread-54591-1-1.html ; https://www.cnblogs.com/yanbinliu/p/6208626.html ; ...