1611
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
全部学习汇总 GreyZhang/g_unix: some basic learning about unix operating system. (github.com)
这一次分析后带有注释的代码我会在笔记最后做一个完整的附加。
这一个例程主要是为了阐述前面讲到的数学运算。但是从这些操作中很多底层的机理还是难以体会到的比如说补码的用法。其实这些都是CPU设计中的一些事情了我们只有在真正关注二进制信息的时候才会有所觉察。
为了能够完成这个例程的编译链接我修改了makefile具体如上。相比上一次笔记中的makefile来说差异点在行号位置也有所标注。其实只是换了一个被编译链接的文件信息。
这部分的设计跟之前的first程序几乎一样直接跳过。这也让人能够稍微有点成就感毕竟前面的积累总归是发挥了作用。
程序最开始的这部分子功能理解很容易这时候寄存器涉及到的不多而且其中的信息都是比较明确的。
整理到这里其实思路也还好。但是到了后面寄存器的内容就有点混乱了。我觉得应该换一个思维模式来解读那就是子功能段开始的时候先规划需要用几个寄存器并且先考虑一个“寄存器内容初始化的动作”。
比如这一段功能其实是在前面的平方基础上乘以输入值。那么我需要的一个输入是之前的平方结果一个是输入值。由此输入至少先需要2个寄存器或者一个另一个直接用存储。做一下这个初始化那就可以先寻找平方存放位置。这个其实是在eax之中。另外需要输入值可以存放在ebx之中。这跟原始的代码设计不同但是我估计可以奏效。
这是按照我自己的想法修改之后的程序测试了一下的确是有相同的效果。
按照上面的思路其实这个地方的ebx换成eax应该也是相同的结果。实际的测试也是如此。这里出现的寄存器副本特别多主要是因为几个函数在反复使用eax导致的。
剩余部分的代码其实也很容易理解。只是这里多了一个值得注意的除法操作通过这个例子可以知道商和余数的存放位置规律。
增加注释后的代码
;
; file: math.asm
; This program demonstrates how the integer multiplication and division
; instructions work.
;
; To create executable:
; nasm -f coff math.asm
; gcc -o math math.o driver.c asm_io.o
%include "asm_io.inc"
segment .data
;
; Output strings
;
prompt db "Enter a number: ", 0
square_msg db "Square of input is ", 0
cube_msg db "Cube of input is ", 0
cube25_msg db "Cube of input times 25 is ", 0
quot_msg db "Quotient of cube/100 is ", 0
rem_msg db "Remainder of cube/100 is ", 0
neg_msg db "The negation of the remainder is ", 0
segment .bss
input resd 1
segment .text
global asm_main
asm_main:
enter 0,0 ; setup routine
pusha
mov eax, prompt
call print_string
call read_int
mov [input], eax
; 在此之前的部分与上一个first程序类似
; 对于读取的数值做一个有符号的自乘
imul eax ; edx:eax = eax * eax
; 把结果转存到ebx这样后面的eax可以用来提供字符串打印功能
mov ebx, eax ; save answer in ebx
mov eax, square_msg
call print_string
; 上面完成了字符串打印功能把转存到ebx的结果搬运回来调用函数打印
mov eax, ebx
call print_int
call print_nl
; 这一段的功能跟上面类似只是乘法不再是自乘而是乘以了一个指定的数值
mov ebx, eax
imul ebx, [input] ; ebx *= [input]
mov eax, cube_msg
call print_string
mov eax, ebx
call print_int
call print_nl
;; 这一段的功能与上一段也是类似的只是这里的乘数不再是指定的数值而是一个固定的数值。
;; 与此同时imul的用法也发生了变化目标参数有了修改
imul ecx, ebx, 25 ; ecx = ebx*25
mov eax, cube25_msg
call print_string
; 这是进行最终结果额度输出还是进行了一次数值的搬运保证调用的函数奏效
mov eax, ecx
call print_int
call print_nl
; 这里的ebx数值来自于56行也就是ebx乘以输入的数值。进一步来自于55行的eax再进
; 一步来自于50行的ebx再进一步来自46行的eax也就是输入数值的平方乘以自身即立方
mov eax, ebx
; eax转换成4字节edx:eax
cdq ; initialize edx by sign extension
mov ecx, 100 ; can't divide by immediate value
; 下面的除法运算的结果商会在eax中存储余数会存储在edx中
idiv ecx ; edx:eax / ecx
; 计算结果做一个存储
mov ecx, eax ; save quotient into ecx
mov eax, quot_msg
call print_string
mov eax, ecx
call print_int
call print_nl
mov eax, rem_msg
call print_string
mov eax, edx
call print_int
call print_nl
; 这部分是一个取反操作
neg edx ; negate the remainder
mov eax, neg_msg
call print_string
mov eax, edx
call print_int
call print_nl
popa
mov eax, 0 ; return back to C
leave
ret