使用git管理代码

什么是git

git是一个分散式版本控制软件,最初由林纳斯·托瓦兹(Linus Torvalds)创作,于2005年以GPL发布。最初目的是为更好地管理Linux内核开发而设计。
git最初的开发动力来自于BitKeeper和Monotone。git最初只是作为一个可以被其他前端(比如Cogito或Stgit[8])包装的后端而开发的,但后来git内核已经成熟到可以独立地用作版本控制。很多著名的软件都使用git进行版本控制,其中包括Linux内核、X.Org服务器和OLPC内核等项目的开发流程。
要使用git版本控制服务,无需自己搭建git服务器,网上有很多免费版本的支持git的代码托管服务,其中最著名的就是github。但是github的免费账户不能创建私有仓库,不适合正在开发或者本身并不开源的软件。因此我们使用bitbucket这个支持私有仓库的网站来托管代码。

注册流程

  1. 访问网站 https://bitbucket.org
  2. 点击Get started for free按钮。
  3. 填好信息,点击Sign up。你也可以直接使用google account注册。
  4. 收到邮件后确认注册。

初始配置

安装git

  1. 这里 可以找到git的安装教程。建议 windows 用户直接下载github的客户端,它附带了一个在windows的Powershell里运行的程序。该软件可以在 这里 找到。

创建SSH密钥对

  1. 创建ssh密钥对。具体过程参考 这里
  2. 将生成的 id_rsa.pub 文件里的内容配置到你的bitbucket账户。具体过程参考 这里

成为 espolito 团队成员

  1. 微信或邮件发给我你的bitbucket帐号。

克隆 esproj 项目

1
2
3
cd <some directory>
git clone git@bitbucket.org:espolito/esproj.git
cd esproj

修改你的默认上传用户

1
2
git config --global user.name "<your name>"
git config --global user.email <your email>

修改代码

  1. 要修改已有的文件,直接修改即可。
  2. 要添加文件,直接新建一个即可。
  3. 要删除已经被服务器同步过的文件,使用命令:
    1
    git rm <file name>

提交代码

每次完成了一部分工作要及时提交到服务器,提交的命令为:

1
2
3
4
cd <to the directory of esproj>
git add .
git commit -m "<some comments to explain your modification>"
git push -u origin master

更新代码

当其他人更新了服务器上的代码之后,你本地所保存的副本就不是最新的。因此每次开始修改代码之前一定要更新代码。更新代码的命令为:

1
git checkout

分享到 评论

Python逆天了

看图,不解释,膜拜…

Python 支持全中文命名

分享到 评论

Barzelletto del giorno

文章

Un enorme toro nero pascola tranquillo su un prato di montagna. A un certo punto nota uno strano movimento, in fondo al pascolo: un puntino bianco che si muove a balzelli verso di lui. Il toro, incuriosito, segue il puntino con lo sguardo, senza però riuscire a capire chi sia: sembra una palla di pelo bianco, che, saltellando, viene verso di lui. Piano piano la palla bianca si avvicina; quando si trova a pochi passi, il toro si accorge che si tratta di un coniglietto bianco. L’animaletto si ferma di fronte al toro. “Ans, ans … caspita che corsa … ans … ehi, ciccione! Fatti da parte che ho fretta!”, grida il coniglietto. Il toro lo osserva ruminando, impossibile. “Ehi, idiota! Non mi hai sentito? Ti ho detto di lasciarmi passare, se no vuoi che ti prenda a calci!”. Il toro continua a ruminare, senza fare una piega. “Ma che hai, le orecchie piene di cerume? Se non ti sposti entro dieci secondi, giuro che ti rompo il muso, capito, ammasso di grasso? Allora … pronto? E unooo dueeee treee quattrooo …”. Emmetendo uno sbuffo di noia, il toro si gira su se stesso, alza la coda, seppellisce il coniglietto sotto una montagna di escrementi e se ne va tranquillo. Passano i minuti, quando una zampetta emerge dalla cima, poi la sconda, infine spunta la testa del coniglietto, tutta imbrattata di cacca. L’animaletto si pulisce gli occhietti, si guarda intorno e, scorto il toro all’orizonte, grida “A-ha! Te la sei fatta sotto, eh!”

生词

  • pascolare [v. i.] 放牧,吃草
  • pascolo [s. m.] 牧场
  • muoversi [v. ref.] 移动
  • balzello [s. m.] 埋伏等待猎物
  • sguardo [s. m.] 看
  • pelo [s. m.] 毛发
  • saltellare [v. i.] 跳动
  • ciccione [s. m.] 大胖子
  • cerume [s. m] 耳垢
  • ruminare [v. i.] 反刍
  • muso [s. m.] 鼻子
  • coda [s. f] 尾巴
  • seppelliscere [s. t.] 埋
  • escremento [s. m.] 粪便
  • cacca [s. f.] 粪便,船尾
  • scorgere [v. t.] 看见

文章

– Qual è l’animale più scemo?
– Il tasso, perché ama le tasse.

生词

  • tasso [s. m] 獾
分享到 评论

嵌入式Linux的移植——编译内核

硬件平台

我们有一块ARM9的开发板,需要装上Linux。ARM芯片的型号是Samsung S3C2440。

Linux版本

自Linux 3.0以后,Linux内核对S3C24xx系列有直接支持,其编译配置文件是参照S3C2410芯片来编写的,
但对该系列都支持。因此无需做任何裁剪即可直接使用该平台编译。

以下是Kernel文档中的说明

1
Configuration
-------------

  A generic S3C2410 configuration is provided, and can be used as the
  default by `make s3c2410_defconfig`. This configuration has support
  for all the machines, and the commonly used features on them.

  Certain machines may have their own default configurations as well,
  please check the machine specific documentation.

因此,我们选择当前最新的稳定内核 Linux 3.19 作为嵌入式linux开发平台。

编译工具链

  • arm-none-eabi-gcc:C语言编译器
  • gnumake:make工具

编译内核

  • http://www.kernel.org下载Linux 3.19
  • 解压压缩包到某个目录下,一般为Linux-3.19,后文统一以$LINUXBUILD取代目录名字。
  • 修改$LINUXBUILD/Makefile中的变量:

    1
    2
    3
    4
    5
    6
    将:
    ARCH ?= $(SUBARCH)
    CROSS_COMPILE ?= $(CONFIG_CROSS_COMPILE:"%"=%)

    修改为:
    ARCH ?= arm # 编译构架为ARM
    CROSS_COMPILE ?= arm-none-eabi- # 编译器前缀为arm-none-eabi-
  • 载入配置文件

    1
    make s3c2410_defconfig
  • 编译

    1
    make
  • 编译后的linux二进制文件为 $LINUXBUILD/arch/arm/boot/zImage

分享到 评论

C语言调用汇编函数

C语言的函数调用

堆栈传参是编译型高级语言通用的传参模式,简单来说就是在调用函数之前将所需要的参数先压栈。在函数内部使用参数指针直接获取参数值。

为了简化,配合DOSBOX中模拟的16位实模式,我们的参数全部使用16位长度参数。

现在我们来看一下标准C编译器是如何编译一个函数调用的。对于以下C语言代码:

1
2
3
4
5
6
7
8
9
int callee(int, int, int);
int caller(void)
{

int ret;

ret = callee(1, 2, 3);
ret += 5;
return ret;
}

默认的,C语言采用__cdecl方式压栈传递参数,函数参数按照从右向左的顺序入栈,函数调用者负责清除栈中的参数,当编译器编译完成之后,反汇编出来的结果为:

1
%注意:以下结果是32位模式的汇编代码,寄存器前面带e的表示extended,即32位寄存器。
caller:
	push	ebp		%压栈bp
	mov 	ebp, esp	%sp=bp,此刻bp指当前栈顶,用于定位参数
	push	3		%传入最后一个参数
	push	2		%传入倒数第二个
	push	1		%传入第一个
	call	callee		%调用子程序
	add 	esp, 12		%将sp加12,相当于执行了三次pop操作
				%(这里是32位模式,每次push和pop都是32bits,也就是4bytes)。
				%该操作弹出,调用函数之前压入的参数。
	add 	eax, 5		%ax存储函数的返回值,ax+5对应原来c语言的ret+=5语句。
	pop 	ebp		%恢复bp
	ret

通过以上例子,我们可以非常清楚地看到C语言的传参过程,而编译器自动生成代码可以令我们通过sp快速定位参数。

C语言的编译过程

与其它编译语言一样,C语言程序的编译过程分为两步:编译(compile)链接(link)。编译,简单来说就是将C语言代码翻译成机器语言的过程;而链接,则是将本程序调用的系统静态和动态库一起打包链接的过程。编译的结果是生产 目标文件,而链接的结果是生成 可执行文件

要在C语言程序中调用汇编语言写的函数,我们需要保证在C语言编译的两个阶段顺利进行。

为了正确的编译,我们需要在C语言中声明,我们需要调用的函数不是来自本程序,而是来自外部的文件。因此,我们需要将该函数声明为 external 。这样,在编译的过程中,编译器才不会因为找不到foo函数的定义而产生错误。编译完成后,会生成一个目标文件,通常以 .o.obj 为后缀。

1
external unsigned short foo(char *);

为了正确的链接,我们需要另一个来自汇编语言的目标文件,在这个文件中我们才真正定义了foo函数。使用MASM生成目标文件的过程叫做 汇编。命令如下:

1
masm test.asm

完成这两步之后,我们就可以使用C语言编译器套件里的链接器将这两个目标文件连同需要的系统库一起链接成可执行文件了。Turbo C编译器的链接器名称为 tlink.exe

其它注意事项

  • 为了保证程序在运行实能找到foo函数的定义。我们需要在汇编代码中将foo函数定义为:

    1
    public _foo
    _foo	proc
    	....
    	ret
    _foo	endp
  • C语言默认将AX的值作为函数返回参数,因此要返回任何值,请直接将其存储在AX中。

分享到 评论

小试python,一个单词记忆软件

词典存储

数据存储可以使用很多方法,最简单的莫过于使用文本文件存储数据。使用文本文件存储数据有诸多好处,比如数据结构直观,可读性强,可以手动修改数据。缺点当然也很多,比如读写速度慢,查找不便等。

在通用文本格式中,主流的有XML、 YAML 以及 JSON。XML具有完备的表达能力,但是读取速度慢,结构复杂;JSON则相反,结构简单,可以直接映射到python内建数据类型,读取速度快,但是表达能力有限;至于YAML,从没用过,不好评论。综合起来,还是选择JSON作为词典的存储结构较为合适。

在结构设计中,我们使用了列表和词典的嵌套。每个词是一个词典类型,包括了“单词”、“词性”、“解释”、“熟悉度”、“稳定熟悉度”以及“更新时间”。除了“熟悉度”和“稳定熟悉度”外,其它都容易理解,而这两个变量将在后面作详细解释。各个词作为列表的元素,组成整个列表。

1
2
3
4
5
[
{"w":"umano", "s":"agg.", "e":"人类的", "f":0, "fs":0, "t":"2015-01-01"},
{"w":"uva", "s":"s. f.", "e":"葡萄", "f":0, "fs":0, "t":"2015-01-01"},
....
]

要读取和写入JSON数据,可以使用json模块,操作非常方便:

1
2
3
4
5
6
7
8
9
import json
# read json data from file
with open("test.dict", "r") as f:
s=json(f)
f.close
# write json object to file
with open("test.dict", "w") as f:
json.dump(s,f)
f.close

概率选词

如何实现根据熟悉程度来决定单词出现的概率呢?我们定义了“熟悉度”这个变量用来存储用户对该单词的熟悉程度。“熟悉度”是一个0~1的浮点数,熟悉度越小,单词越容易被选中,反之亦然。

从熟悉度到概率(或称之为权重或频率)的转化非常简单。只需要用1减去熟悉度就得到了该词应该出现的频率。

现在我们需要设计一个函数,给定一个概率分布就自动按该概率分布选择一个词。因为我们的词在字典里是数组元素,因此该问题可以简化为,给定一个概率分布数组,自动按概率选出一个索引值整数。

我们需要借助random模块的random函数。random.random()返回一个0~1的浮点数。该随机数可以看作是均匀分布的。

我们先求出所有单词概率的和,将其看成是一个长度a。概率大的单词占有a的空间大,概率小的单词占有的空间小,这个占有空间用s表示。在长度a内使用随机分布的得到一个点B,它距离原点的距离是b。那么B落到各个单词占有空间内的概率就与各个单词占有的空间成正比。

例如,对于3个单词的概率分布f=[0.2,0.4,0.7]来说:
s=sum(f)=0.2+0.4+0.7=1.3
b=random.random() * s
那么,b落在(0,0.2)区间的概率就是0.2/1.3;而落在(0.2,0.6)区间的概率就是0.4/1.3;落在(0.6,1.3)区间的概率就是0.7/1.3。

一旦点B落在了某个单词所属的空间,则返回该概率的索引。这个索引的获取可以通过减去点B之前的概率空间而确定。以前面的例子为例,加入B点落在0.8座标处,那么就用0.8循环减去概率列表的每一个值,直到0.8被剪到一个负值为止。这时候的索引就是我们需要的索引。

初始值:b=0.8
第一次减法:b=b-f[0]=0.8-0.2=0.6
第二次减法:b=b-f[1]=0.6-0.4=0.2
第三次减法:b=b-f[2]=0.2-0.7=-0.5 <– 出现负值
因此,这时候的索引值2就是需要返回的索引值。该索引等于单词的索引,从而就可以与熟悉度相关地产生出一个单词了。

1
2
3
4
5
6
def get_index_by_weight(self,weights):
rnd = random.random() * sum(weights)
for i, w in enumerate(weights):
rnd -= w
if rnd < 0:
return i

记忆曲线

待续 …

分享到 评论

意大利简史 —— 从罗马帝国到今天

文章

La culla della civilizzazione europea 欧洲文明的摇篮

La città di Roma fu fondata già nel 753 a.C. secondo la storiografia romana; due secoli dopo Roma diventò la capitale di un emergente Impero Romano. Gli Antichi Romani conquistarono passo dopo passo l´area mediterranea e mezza Europa e poserò le basi per la civilizzazione di oggi. Il diritto romano, il cattolicesmio, l´arte e la cultura così come il progresso tecnico caratterizzarono non soltanto la storia d´Italia, ma anche la storia dell´intero mondo occidentale. Il periodo aureo trovò la sua fine dopo la scissione dell´Impero Romano in due parti, quella occidentale e quella orientale. Mentre l´Impero Romano d´Oriente continuò ad esistere fino al 1453, il regno romano in Italia si concluse in seguito alle continue invasioni da parte di popoli stranieri e alla conquista definitiva di Roma da parte di Odoacre nell´anno 476 d.C.

据罗马史记载,罗马城建于公元前753年;两个世纪后,罗马便成为了新兴罗马帝国的首都。古罗马人慢慢征服了地中海地区和半个欧洲并为如今的文明奠定基础。罗马法、天主教、艺术和文化,就这样随着技术进步它们不仅展现了意大利的历史,还展现了整个西方世界的历史。这个黄金时代终结于罗马帝国的分裂,最终形成了西罗马帝国和东罗马帝国。东罗马帝国一直延续到了1453年,而意大利的罗马帝国却在接连的外族入侵和公元476年被奥多亚赛征服下最终落幕。

###Storia movimentata – L´Italia nel Medioevo 多事之秋 – 中世纪的意大利

Poco dopo la caduta dell´Impero Romano, l´Italia diventò il giocattolo delle nuove potenze europee. Germani, Ostrogoti e Longobardi regnavano l´uno dopo l´altro diverse zone della penisola e caratterizzarono l´Italia in parte fino ai nostri tempi. L´aumento del potere del Papato e l´ascesa dei Franchi portarono finalmente alla distruzione del regno longobardo e alla divisione del paese in tre parti: il Sacro Romano Impero Germanico al nord, lo stato pontificio nel centro e diverse potenze che si alternarono a regnare il sud dell´Italia. Con lo sviluppo della borghesia e durante la lotta per le investiture tra papa e imperatore si formarono delle città stato nell´Italia settentrionale e centrale che influenzarono la storia dell´Italia fino all´età moderna.

罗马帝国陨落后不久,意大利便成为了欧洲新兴力量的玩具。德国人、东哥特人及伦巴底人一个接一个地统治着半岛的不同地区并代表着各自的意大利直到我们的时代。罗马教皇的权利增加和法兰克人的增长最终导致了伦巴底王国的覆灭并将意大利分裂为三部分:北部的神圣罗马帝国、中部的教皇国和交替统治意大利南部的不同力量。随着资产阶级的发展,当教皇和皇帝为争夺天职而战斗时,许多城邦在意大利北部和中部形成了,它们一直影响意大利的历史直到现代时期。

###Storia d´Italia – Dall´fino ad oggi 意大利历史 – 从统一到今天

Dopo un lungo periodo buio, l´Italia riconquistò il primato culturale ed economico nell´Europa per un breve periodo nel XV secolo. Le potenti città stato italiane erano il centro dell´umanismo e rinascimento. Con la scoperta dell´America, l´Italia perse ben presto questo primato e diventò nuovamente il giocattolo delle nuove potenze europee Francia e Austria. Le repubbliche città italiane furono unite per la prima volta dopo la caduta dell´Impero Romano sotto Napoleone che proclamò il Regno d´Italia e incoronò se stesso re d´Italia. In seguito alla diffusione sempre più larga del nazionalismo, i popoli italiani si ribellarono contro l´Austria e fondarono nel 1861 il regno d´Italia. La voglia di ristabilirsi come una grande potenza finì nella Prima Guerra Mondiale, dalla quale l´Italia uscì certamente come vincente, ma che procurò al paese problemi economici e sociali, spianando la strada al Fascismo. Dopo la Seconda Guerra Mondiale nel 1946 l´Italia fu proclamata repubblica parlamentare ed essendo anche paese fondatore dell´Unione Europea ritrovò il suo posto in Europa.

黑暗时期以后,意大利在十五世纪一小段时间内又重回了欧洲文化和经济的重要地位。强大的意大利城邦是人文主义和文艺复兴的中心。随着美洲大陆的发现,意大利很快就失去了这个地位并重新沦为新欧洲力量的玩具,它们是法兰西和奥地利。意大利城邦共和国们在罗马帝国摇篮时期后第一次由拿破仑统一,称为意大利王国,拿破仑自己加冕为意大利国王。接着随着民族主义传播,意大利人民将自己从奥地利的控制下解放出来并于1861年成立意大利王国。重新确立重要权力的渴望在第一次世界大战中结束,其中,意大利毫无疑问是战争的赢家,但也导致了经济和社会问题,为走向法西斯主义铺平了道路。1946年第二次世界大战结束以后意大利宣告成立议会制共和国并作为欧盟创始国重新找到了自己在欧洲中的位置。

语法

远过去时 Passato remoto

用法

  • 表示很久以前发生的动作,历史事件,与现在无关的动作
  • 表示说话者漠不关心的动作,表示动作与说话者心理距离很远
  • 童话和小说中的书面表达
  • 某些意大利南部和中部地区的人喜欢用

规则动词变位

parlare credere capire
io parlai credei(-etti) capii
tu parlasti credesti capisti
lui/lei/Lei parlò credè(-ette) capì
noi parlammo credemmo capimmo
voi parlaste credeste capiste
loro parlarono crederono(-ettero) capirono

不规则动词变位

essere avere fare
io fui ebbi feci
tu fosti avesti facesti
lui/lei/Lei fu ebbe fece
noi fummo avemmo facemmo
voi foste aveste faceste
loro furono ebbero fecero
分享到 评论

如何安装TeXLive

警告

TeX不是MS Office (Word)。在使用TeX时,请确保已经学会的所有Word技能已经遗忘。

安装TeXLive

请参考这篇文章:
http://www.math.zju.edu.cn/ligangliu/latexforum/tex_setup.htm
这篇文章写得非常详细了,就不用我再浪费能量解释了。只是还需要稍稍说明一下在Windows上的操作:

如何解压ISO文件

使用7-zip、winrar均可以直接解压以ISO为后缀名的光盘镜像文件。

如何选取安装目录

任何windows目录均可以作为安装目录,但是需要目录下的文件组织结构和参考文章中的一致。

如何修改PATH环境变量

参考Oracle的Java安装指南中的修改环境变量一节,很详细。
https://www.java.com/zh_CN/download/help/path.xml
请注意,这里的修改PATH环境变量是指将TexLive的bin目录下的文件路径添加到PATH里,而不是覆盖原来的PATH变量。

使用TeXLive

参考入门教程
[英文]LaTeX的入门教程,简略地介绍了重要语法
[中文]比较详细的LaTeX语法介绍
TeX在线公式编辑器,可以方便直观地输入数学公式

分享到 评论

dB/dec 与 dB/oct

基本概念

什么是分贝(dB)

分贝(deci-bel)是度量两个相同单位数量比例的单位,主要用于声音测量。
分贝的计算方法根据被比较量的不同而不同。物理世界中需要用分贝表示比例的物理量可以分为两类:功率量场量

功率量的计算方法:

场量的计算方法:

为什么区分功率量和场量?

因为对于大多数应用,功率量与场量幅值的平方成比例,我们期望对同一应用采取功率计算的分贝与用场的幅值计算的分贝相等。因此,对功率计算分贝采用直接比较,而对场量计算分贝则用平方比较。例如,在电路中有:

因此,对功率量来说有:

而对场量电压来说有:

什么是dec

dec是decade的缩写,表示10。一个decade指两个数相差10倍,通常用于以10为底的对数座标。

比如,decade可以用于波特图中的横座标。如下图所示:
decade in “Bode plot”

什么是oct

oct是octave的缩写,表示8,最初指音乐中的8个自然音阶,每个音阶都是前一个音阶的2倍频率,因此octave引申为倍频或者半频。通常用于以2为底的对数座标。

dB/dec与dB/oct的关系

dec与oct其实就是对数的底不同,要推导它们之间的关系。
我们首先假设一条频率衰减曲线上有两个信号频率关系为 1oct

它们的分贝比为:

因此,在以2为底(oct)的横座标座标系中,相差1个oct的频率,它们之间的分贝偏差 为6dB。
我们再假设在相同的频率衰减曲线上有两个信号的频率关系为 1dec

它们的分贝比为:

因此,在以10为底(dec)的横座标座标系中,相差1个dec的频率,它们之间的分贝偏差为20dB。
我们可以得出结论:
对同一条曲线,若以dec为横座标,20dB相当于以oct为横座标的6dB。它们都表示同一条曲线。
即:

例子

在波特图上有一条衰减曲线,它在f0之前均保持40dB(设此时电压为V0)。在f0之后,便以20dB/dec的斜率衰减。请问,在以频率f为横座标的正常座标系中,频率为2f0处的电压幅值为多少?

因为,

所以,该曲线的衰减部分的斜率可以表示为6.06206dB/oct。2f0与f0相差一个oct,因此,2f0处相对于f0处会衰减6.06206dB:

所以:

分享到 评论

使用汇编语言输出内存数据

我们知道如何使用 21H 中断处理I/O, 知道如何将各种进制的数据相互转换。那么问题来了:如何用8086汇编语言优雅地输出一段内存呢?

让我们从最简单的开始:

以 16 进制格式输出一个 Byte

原理

一个 Byte 为 8 位,每 4 位可以用一个 16 进制的数表示,因此,一个 Byte 可以用两个 16 进制数表示。例如,19(Dec) = 00010011(Bin) = 13(Hex)。

若要输出到屏幕上,我们还需要把 16 进制数字转化为对应的 ASCII 字符。对于 0<=Num(Hex)<=9,它们和与之对应的 ASCII 字符相差 30H, 也就是 ‘0’ 的ASCII 字符码。即,Num(ASCII) = Num(Hex) + ‘0’。同理,对于 A<=Num(Hex)<=F ,Num(ASCII) = Num(Hex) + ‘A’。

编码

1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; FUNC: write_hex
; ARGS: dl -- the byte to be print
; RETS: void
; DESC: print a byte in HEX format
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
write_hex	proc
	push	ax
	push	cx
	push	dx
	mov	ah, 2h
	mov	dh, dl
	mov	cl, 4
	shr	dl, cl
	and	dl, 0fh
	cmp	dl, 0ah
	jl	write_hex_add0
	sub	dl, 0ah
	add	dl, 'A'
	jmp	write_hex_over0
write_hex_add0:
	add	dl, '0'
write_hex_over0:
	int	21h
	mov	cl, 8
	shr	dx, cl
	and	dl, 0fh
	cmp	dl, 0ah
	jl	write_hex_add1
	sub	dl, 0ah
	add	dl, 'A'
	jmp	write_hex_over1
write_hex_add1:
	add	dl, '0'
write_hex_over1:
	int	21h
	pop	dx
	pop	cx
	pop	ax
	ret
write_hex	endp

以 16 进制格式输出 N 个 Byte

原理

要输出N个 Byte,只需要循环 N 次调用函数 _writehex 即可。

编码

1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; FUNC:	dump_mem
; ARGS:	si -- the starting address
;	cx -- the number of units
; RETS:	void
; DESC:	write a range of memory to std output in HEX
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
dump_mem	proc
	push	ax
	push	cx
	push	dx
	push	si
	mov	ah, 02h
dump_mem_lop1:
	mov	dl, [si]
	call	write_hex
	inc		si
	mov	dl, 'H'
	int	21h
	mov	dl, ' '
	int	21h
	loop	dump_mem_lop1
	pop	si
	pop	dx
	pop	cx
	pop	ax
	ret
dump_mem	endp

以 16 进制格式输出 N 个 Byte 或 Word 或 Double Word

原理

终于到了最“优雅”的阶段了,我们函数才是我们最希望看到的,可以配置 BX 从而配置输出单元的大小。

需要注意的一点是:Intel CPU采用小端对齐(Little Endian)。也就是说一个数的最低位在内存当中的地址也是最小的。比如地址为 10000H 的 Word 类型的数据内容是 1234H,那么数据 12H 的地址就是10000H,而数据 34H 的地址就是10001H。

小端对齐的特性让我们的问题有点棘手,因为对于每个 Word 或 Double Word 类型,我们都需要先输出高位,再输出低位。也就是说先要输出高地址部分,再输出低地址部分。因此指针的移动方向就会变成双向的。例如,我们要输出地址 10000H 开始的 Word 型数据。指针的移动就会变成:

1
10001H -> 10000H -> 10003H -> 10002H -> 10005H -> 10004H ....

因此,我们需要两个嵌套的循环才能处理。

编码

1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; FUNC:	dump_mem
; ARGS:	si -- the starting address
;	cx -- the number of units
;	bx -- the unit size (1 for B, 2 for W, 4 for DW)
; RETS:	void
; DESC:	write a range of memory to std output in HEX
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
dump_mem	proc
	push	ax
	push	bx
	push	cx
	push	dx
	push	si
	mov	ah, 02h
dump_mem_lop1:
	push	cx
	mov	cx, bx
	push	bx
	sub	bx, 1
dump_mem_lop2:
	mov	dl, [si+bx]
	call	write_hex
	dec	bx
	loop	dump_mem_lop2
	pop	bx
	pop	cx
	mov	dl, 'H'
	int	21h
	mov	dl, ' '
	int	21h
	add	si, bx
	loop	dump_mem_lop1
	pop	si
	pop	dx
	pop	cx
	pop	bx
	pop	ax
	ret
dump_mem	endp

所有代码可在 https://github.com/herenvarno/LibMasm16 找到。该项目以 MIT协议 授权。

分享到 评论