高级语言里的函数在汇编里的实现方式

一、 学习过程

在高级语言中我们为什么要用变量呢?因为我们要存储数据,而且因为要使用循环等语法结构,存储的数据需要不断地变化,变量的特性可以很好地解决这个问题。在前面我已经讨论过了,变量的声明实际上就是在内存中开辟一个内存空间,我们在汇编语言里使用循环,主要是把数据存在si、di等寄存器中来进行操作,存储数据是把数据放在寄存器、内存空间(普通的和栈)里面。编写程序ur1.c,并编译连接:

用debug加载ur1.exe,用u命令查看编译后的机器码和汇编代码:

发现main函数中的代码没有出现,用t命令单步执行发现程序在一个死循环内,为什么这时显示的代码不是main函数里的代码呢?可能的原因有两个:(1)我以为main函数里的代码编译后会是这样:mov ax,1;mov bx,1;mov cx,1;mov ax,bx;add ax,cx……但是c语言编译成的汇编代码是通过别的方式实现代码的功能的,与我从汇编的角度来实现功能的方式不一样。(2)main函数本身经过编译后会有许多汇编代码,或者是main函数前面还要加载其他程序,导致main函数里的代码被放在一个我们不知道的地方,所以找不到。那么main函数的代码在什么段中?用debug怎样找到ur1.exe中main函数的代码?我觉得应该在code段中,但是程序里没有标号,看不到main的地址。那么就写一个main到程序里,看看main的地址是多少。

编译程序,显示main函数的偏移地址:

运行发现,main函数的偏移地址为1fa:

那么,用debug运行ur1.exe,找到main函数的地址:

由图可知,ur1.c中对应的代码是mov ax,1;mov bx,1;mov cx,2;mov ax,bx;

add ax,cx;mov ah,bl;add ah,cl;mov al,bh;add al,ch.这里还应注意到开头和结尾的三条指令:push bp;mov bp,sp;pop bp.是对bp进行了保护,并且在程序中把sp赋给了bp,为什么要这样做呢?书本上的解释是:这是C编译器安排的为函数中可能使用到bp寄存器而设置的。那么为什么函数中可能使用到bp寄存器呢,也可能使用到别的寄存器啊,为什么只对bp寄存器进行了保护?

还有在代码结尾处用ret进行了处理,即对ip出栈,一般用到ret时会与call指令配合使程序段成为可调用的字程序段,那么main函数是以call-ret的方式来实现成为子程序段的吗?将以下程序编译连接:

用debug查看main函数中的内容:

发现果然f()的位置被call 020b代替。而20b的位置上是f()函数的内容:

所以我们的想法是正确的,不仅main函数在汇编语言里是以call-ret程序段的方式实现的,甚至C语言是将所有函数都实现为汇编语言里的call-ret子程序段。

二、 解决的问题

(1) 为什么用debug查看ur1.exe文件找不到main函数里的内容?

答:因为main函数及其内容是作为子程序段被放在其他位置,所以找不到。

(2) 用debug怎么查找函数的偏移地址?

答:写一个程序,用printf打印函数的地址。

(3) C语言里的函数在汇编语言里是怎样实现的?

答:用call-ret作为子程序段来实现。

三、 未解决的问题

(1) 为什么一个函数在汇编语言中实现要对并且只对bp寄存器进行保护?

(2) 为什么用debug加载ur1.exe用u命令首先看到的不是main函数及其内容,而是一大堆无关的指令?

(3) 其他高级语言函数的实现方式和C语言一样吗?

四、学习感想

你的想法到底正不正确呢?试一试就知道了,实践是检验真理的唯一标准。很多时候我们都会觉得尝试是一件很麻烦的事,所以面对还不太懂的问题,就想当然地给它下一个判断,或者根本不去想,等别人来告诉你,久而久之,我们对一件事物的整个认知就会出现偏差,从而犯错。函数名能够直接写在printf函数里把地址打印出来吗?c语言里的函数是用什么形式在汇编语言里实现的呢?这些都是需要亲自尝试才能解决的问题。在平时的学习和生活中,我们经常会遇到诸如此类的问题,但是有时候因为自身的惰性,想当然地把它忽视掉了,要用到的时候才感叹自己知道的真的太少。所以,保持一个积极强烈的求知心态是学习过程中很重要的。

时间: 2024-10-15 20:55:50

高级语言里的函数在汇编里的实现方式的相关文章

Swift # 柯里化函数

前言 此次文章,讲述的是Swift的一个新特性(柯里化函数),可能很多iOS开发人员是第一次听这个词汇,包括我自己也是,自己也用了几天时间才总结出来,希望能帮助到各位咯,个人感觉偏向有开发经验的码友,如果零基础的看懂,希望能给个赞,??! 如果喜欢我的文章,可以关注我,随着后续不断学习Swift中,陆续还会有更新ing.... 什么是柯里化函数? 柯里化(Currying),又称部分求值(Partial Evaluation),是一种函数式编程思想,就是把接受多个参数的函数转换成接收一个单一参数

javascript中利用柯里化函数实现bind方法

柯理化函数思想:一个js预先处理的思想:利用函数执行可以形成一个不销毁的作用域的原理,把需要预先处理的内容都储存在这个不销毁的作用域中,并且返回一个小函数,以后我们执行的都是小函数,在小函数中把之前预先存储的值进行相关的操作处理即可: 柯里化函数主要起到预处理的作用: bind方法的作用:把传递进来的callback回调方法中的this预先处理为上下文context; /** * bind方法实现原理1 * @param callback [Function] 回调函数 * @param con

浅谈JavaScript中的柯里化函数

首先,不可避免的要引经据典啦,什么是柯里化函数呢(from baidu): 在计算机科学中,柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术.这个技术由 Christopher Strachey 以逻辑学家 Haskell Curry 命名的,尽管它是 Moses Schnfinkel 和 Gottlob Frege 发明的. 用于创建已经设置好了一个或多个参数的函数 与函数绑定相似,他们之间的区

【Scala】高阶函数和柯里化

高阶函数 在数学和计算机科学中,高阶函数是至少满足下列一个条件的函数: - 接受一个或多个函数作为输入 - 输出一个函数 在数学中它们也叫做算子(运算符)或泛函.微积分中的导数就是常见的例子,因为它映射一个函数到另一个函数. 高阶函数的例子 假设有一个函数对给定两个数区间中的所有整数求和: def sumInts(a: Int, b: Int): Int = if(a > b) 0 else a + sumInts(a + 1, b) 如果现在要求连续整数的平方和: def square(x:

JavaScript的柯里化函数

柯里化,或者说部分应用,是一种函数式编程的技术,对于熟悉以传统方式编写 JavaScript 代码的人来说可能会很费解.但如果使用得当,它可以使你的 JavaScript 函数更具可读性. 更具可读性和灵活性 函数式 JavaScript 被吹捧的优点之一就是拥有短小紧凑的代码风格,可以用最少行数.更少重复的代码得到正确的结果.有时这会以牺牲可读性为代价:如果你还不熟悉函数式编程的方法,这种方法写的代码会很难阅读和理解. 如果之前你遇到过柯里化这个术语,但是不知道它是什么意思,把它当做奇怪的.难

关于函数里和函数外的变量/类/常量的

关于函数里和函数外的变量/类/常量的     1 变量是不能跨越到函数里面的,即函数外面的变量不能直接在函数里面使用,函数里面的变量更不能被函数外面使用 2 类可以跨越到函数里面,但是不能实例化之后赋给一个变量再在函数里用,这样相当于变量,而变量是不能跨越到函数里的 3 常量 有些复杂,(其实也好理解) 常量的作用范围是本次页面   具体如下 ①: 函数外定义,函数里可以使用 define("AAA","Good"); function a(){ echo AAA;

[转]html页面调用js文件里的函数报错onclick is not defined处理方法

原文地址:http://blog.csdn.net/ywl570717586/article/details/53130863 今天处理html标签里的onclick功能的时候总是报错:Uncaught ReferenceError: dosave is not defined(-) 找了半天都没发现错在哪,最后发现原来是我写法不对,正确写法如下: html: [html] view plain copy <input type="button" value="立即登录

CTEX里的函数、符号及特殊字符

CTEX里的函数.符号及特殊字符 声调 语法 效果 语法 效果 语法 效果 \bar{a}   \acute{a}   \check{a}   \grave{a}   \tilde{a}   \hat{a}   \breve{a}   \dot{a}   \ddot{a}   函数 语法 效果 语法 效果 语法 效果 \sin a sina \cos b cosb \tan c tanc \arcsin d arcsind \arccos e arccose \arctan f arctanf

浅析 JavaScript 中的 函数 currying 柯里化

原文:浅析 JavaScript 中的 函数 currying 柯里化 何为Curry化/柯里化? curry化来源与数学家 Haskell Curry的名字 (编程语言 Haskell也是以他的名字命名). 柯里化通常也称部分求值,其含义是给函数分步传递参数,每次传递参数后部分应用参数,并返回一个更具体的函数接受剩下的参数,这中间可嵌套多层这样的接受部分参数函数,直至返回最后结果.因此柯里化的过程是逐步传参,逐步缩小函数的适用范围,逐步求解的过程. 柯里化一个求和函数 按照分步求值,我们看一个