云班课学习内容

一、C语言中嵌入汇编代码

1、内嵌汇编语法

(1)C语言中嵌入汇编代码的写法:

asm(

汇编语句模板:

输出部分:

输入部分:

破坏描述部分);

说明:输出部分和输入部分对应着C语言中的函数调用时的参数(return也是一个输出部分)

例:

printf("val1:%d,val2:%d,val3:%d\n",val1,val2,val3);
asm volatile(
/*asm是GCC关键字asm的宏定义,表示内嵌汇编语句,与__sam__同,volatile是GCC关键字volatile的宏定义,告诉编译器不要对代码进行优化,与__volatile同*//
"movl $0,%%eax\n\t" /*clear %eax to 0,两个%中第一个用于转义*/
"addl %1,%%eax\n\t" /*%eax+=val1,是输入输出中的第二个数*/
"addl %2,%%eax\n\t" /*%eax+=val2,是输入输出中的第三个数*/
"movl %%eax,%0\n\t" /*val3=%eax*/
:"=m"(val3) /*output=m,只写,m表示写入内存
:"c"(val1),"d"(val2) /*input c:ecx d:edx*/
);
printf("val1:%d+val2:%d=val3:%d\n",val1,val2,val3); return 0;

(2)内嵌汇编常用限定符

限定符 描述
“a” 将输入变量放入eax
“b” 将输入变量放入ebx
“c” 将输入变量放入ecx
“d” 将输入变量放入edx
“s” 将输入变量放入esi
“D” 将输入变量放入edi
“q” 将输入变量放入eax,ebx,ecx,edx中的一个
“r” 将输入变量放入通用寄存器,也就是eax,ebx,ecx,edx,esi,edi中的一个
“A” 放入eax和edx,吧、把eax和edx合成一个64位的寄存器
“m” 内存变量
“o” 操作数为内存变量,但是其寻址方式是偏移量类型
“V” 操作数为内存变量,但寻址方式不是偏移量类型
“.” 操作数为内存变量,但寻址方式是自动增量
“p” 操作数是一个合法的内存地址(指针)
“g” 将输入变量放入eax,ebx,ecx,edx中的一个或者作为内存变量
“X” 操作数可以是任何类型
“I” 0-31之间的立即数(用于32位移位指令)
“J” 0-63之间的立即数(用于64位移位指令)
“N” 0-255之间的立即数(用于out指令)
“i” 立即数
“n” 立即数,有些系统不支持数字以外的立即数,这些系统应该使用n
“=” 操作数在指令中是只写的(输出操作数)
“+” 操作数在指令中是读写类型的(输入输出操作数)
“%” 该操作数可以和下一个操作数交换位置

二、三个法宝:存储程序计算机、函数调用堆栈、中断

1、计算机是如何工作的?(总结)--三个法宝

(1)存储程序计算机:所有计算机基础性的逻辑框架。

(2)函数调用堆栈:计算机中非常基础性的东西。最早的计算机没有高级语言,只有机器语言和汇编语言时没有函数的概念。而高级语言中有函数的概念,需要堆栈机制,是高级语言可以运行的基础。

堆栈是C语言程序运行时必须的一个记录调用路径和参数的空间。

--函数调用框架

--传递参数

--保存返回地址(保存返回值,如eax)

--提供局部变量空间

--等等

C语言编译器对堆栈的使用有一套规则,同一段C语言程序在不同的操作系统中产生的汇编代码可能会有一些差异。

了解堆栈存在的目的和编译器对堆栈使用的规则是理解操作系统一些关键性代码的基础。

(3)中断:计算机帮程序员做的一些工作。

中断

早期计算机没有中断时,需要执行完一个程序之后再执行另一个程序。

有了中断,就有了多道程序设计,即在系统中同时跑多道程序。

当中断发生时,CPU会把当前的eip,esp,ebp都压到一个内核堆栈中。CPU和内核代码共同实现了保存和回复现场。

2、利用mykernel实验模拟计算机硬件平台。

(1)搭建一个虚拟平台

(2)使用Linux源代码把CPU的配置配置好

(3)执行

cd LinuxKernel/Linux-3.9.4
qeum -kernel arch/x86/boot/bzImage /*加载内核*/

实验中遇到问题



①编译Linux内核出现include/linux/compiler-gcc.h:103:30: fatal error: linux/compiler-gcc5.h: No such file or directory

解决方案





解决方案:将用户转换为root即可

编译中:



完成:

qemu -kernel arch/x86/boot/bzImage



在mykernel目录中:



cd mykernel

输入ls命令会发现,该文件夹中含有mymain.c和myinterrupt.c两个文件。

/*mymain.c中开始启动操作系统,入口*/
void __init_my_start_kernel(void)
{
int i = 0;
while(1)
{
i++;
if(i%100000 == 0)
printk(KERN_NOTICE "my_start_kernel here %d \n",i);/*每循环十万次,打印一条消息*/
}

void my_timer_handler(void)/*myinterrupt.c中,时钟中断处理入口*/
{
printk(KERN_NOTICE "\N>>>>>>>>>>>>>>>>>>>>>my_timer_handler here <<<<<<<<<<<\n\n");
}

当按照课本敲完代码只有,出现了很多错误,都是因为敲代码的时候不认真,多了字母、少了字母或者是代码敲错。其中值得一提的一个错误是在mymain.c文件中的初始化函数,init前面是两个下划线,而不是一个。

之后运行成功:

三、深入理解函数调用堆栈

1、(1)esp:堆栈指针

(2)ebp:基址指针

(3)堆栈操作:①push栈顶地址减少4个字节(32位)

②pop栈顶地址增加4个字节(32位)

(4)ebp在C语言中用作记录当前函数调用基址

(5)其他关键寄存器

cs:eip总是指向下一条的指令地址

顺序执行:总是指向地址连续的下一条指令

跳转/分支:执行这样的指令的时候,cs:eip的值会根据程序需要被修改

call:将当前cs:eip的值压入栈顶,cd:eip指向被调用函数的入口地址

ret:从栈顶弹出原来保存在这里的cs:eip的值,放入cs:eip中

(6)建立被调用者函数的堆栈框架

pushl %ebp
movl %esp,%ebp
/*被调用者函数体*/
/*拆除被调用者函数的堆栈框架*/
movl %ebp,%esp
popl %ebp
ret

2、堆栈调用

(1)首先使用gcc -g生成test.c的debug版本的可执行文件test,然后使用objdump -S 获得test的反汇编文件。

    objdump -S test > test.txt



注意为什么在反汇编代码中,是用变址寻址,而不是直接用x或者y?

是因为:参数已经放在了堆栈中,只需要根据地址寻找即可。

2019-2020-1 20199302《Linux内核原理与分析》第三周作业的更多相关文章

  1. 2019-2020-1 20199329《Linux内核原理与分析》第九周作业

    <Linux内核原理与分析>第九周作业 一.本周内容概述: 阐释linux操作系统的整体构架 理解linux系统的一般执行过程和进程调度的时机 理解linux系统的中断和进程上下文切换 二 ...

  2. 2019-2020-1 20199329《Linux内核原理与分析》第二周作业

    <Linux内核原理与分析>第二周作业 一.上周问题总结: 未能及时整理笔记 Linux还需要多用 markdown格式不熟练 发布博客时间超过规定期限 二.本周学习内容: <庖丁解 ...

  3. 20169212《Linux内核原理与分析》第二周作业

    <Linux内核原理与分析>第二周作业 这一周学习了MOOCLinux内核分析的第一讲,计算机是如何工作的?由于本科对相关知识的不熟悉,所以感觉有的知识理解起来了有一定的难度,不过多查查资 ...

  4. 20169210《Linux内核原理与分析》第二周作业

    <Linux内核原理与分析>第二周作业 本周作业分为两部分:第一部分为观看学习视频并完成实验楼实验一:第二部分为看<Linux内核设计与实现>1.2.18章并安装配置内核. 第 ...

  5. 2018-2019-1 20189221 《Linux内核原理与分析》第九周作业

    2018-2019-1 20189221 <Linux内核原理与分析>第九周作业 实验八 理理解进程调度时机跟踪分析进程调度与进程切换的过程 进程调度 进度调度时机: 1.中断处理过程(包 ...

  6. 2017-2018-1 20179215《Linux内核原理与分析》第二周作业

    20179215<Linux内核原理与分析>第二周作业 这一周主要了解了计算机是如何工作的,包括现在存储程序计算机的工作模型.X86汇编指令包括几种内存地址的寻址方式和push.pop.c ...

  7. 2019-2020-1 20209313《Linux内核原理与分析》第二周作业

    2019-2020-1 20209313<Linux内核原理与分析>第二周作业 零.总结 阐明自己对"计算机是如何工作的"理解. 一.myod 步骤 复习c文件处理内容 ...

  8. 2018-2019-1 20189221《Linux内核原理与分析》第一周作业

    Linux内核原理与分析 - 第一周作业 实验1 Linux系统简介 Linux历史 1991 年 10 月,Linus Torvalds想在自己的电脑上运行UNIX,可是 UNIX 的商业版本非常昂 ...

  9. 《Linux内核原理与分析》第一周作业 20189210

    实验一 Linux系统简介 这一节主要学习了Linux的历史,Linux有关的重要人物以及学习Linux的方法,Linux和Windows的区别.其中学到了LInux中的应用程序大都为开源自由的软件, ...

  10. 2018-2019-1 20189221《Linux内核原理与分析》第二周作业

    读书报告 <庖丁解牛Linux内核分析> 第 1 章 计算工作原理 1.1 存储程序计算机工作模型 1.2 x86-32汇编基础 1.3汇编一个简单的C语言程序并分析其汇编指令执行过程 因 ...

随机推荐

  1. python实现查找最长公共子序列

    #!/usr/bin/python # -*- coding: UTF-8 -*- worlds = ['fosh','fort','vista','fish','hish','hello','ohd ...

  2. python 之网络并发(非阻塞IO模型)

    实现gevent模块 服务端: from socket import * import time s = socket() s.bind(('127.0.0.1',8080)) s.listen(5) ...

  3. day30——socket套接字(完全版)

    day30 基于TCP协议的socket循环通信 server import socket phone = socket.socket() phone.bind(("127.0.0.1&qu ...

  4. AX 2009中Set运用

    Set运行: 例子: Set m_set = new Set(Types::String); m_set.add("AAA"); m_set.add("BBB" ...

  5. es6新特性-解构表达式、Lambda表达式、局部变量及map/reduce方法

    循环内的变量在循环外可见,不合理: let定义的变量是局部变量: const修饰的是常量,不允许再次修改,类似于java中的static: 解构表达式:

  6. Windows中的消息与消息队列

    消息 在Windows中,消自由MSG结构体表示 typedef struct tagMSG { HWND hwnd; UINT message; WPARAM wParam; LPARAM lPar ...

  7. C# vb .net实现不透明度调整特效滤镜

    在.net中,如何简单快捷地实现Photoshop滤镜组中的不透明度调整呢?答案是调用SharpImage!专业图像特效滤镜和合成类库.下面开始演示关键代码,您也可以在文末下载全部源码: 设置授权 第 ...

  8. js 页面技巧

    需要获取页面上固定的某个按钮的属性值.我们需要在页面加载完的第一刻将值存储到定义的变量,防止用户更改页面样式读不出当前元素.如果页面刷新会重置当前属性 <body> <input v ...

  9. Git提交代码解决方案

    最近做项目不再用小乌龟了,开始用git,便做了记录如下,后期可以看看自己是怎么使用的   下载安装就不说了,直接进入使用环节.   1.使用规则 git pull origin master 和 gi ...

  10. 如何使用NPM?CNPM又是什么?

    背景介绍 什么是npm? npm(node package manager)是nodejs的包管理器,用于node插件管理(包括安装.卸载.管理依赖等), NPM是随同NodeJS一起安装的包管理工具 ...