| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 7613 人关注过本帖
标题:大家来写写汇编小玩意
取消只看楼主 加入收藏
Valenciax
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:11
帖 子:340
专家分:2482
注 册:2016-5-15
结帖率:100%
收藏
已结贴  问题点数:20 回复次数:8 
大家来写写汇编小玩意
汇编一向是小众玩意,普遍认为写复杂程式挺烦,版面冷清是常态。
好吧,大的不想写,不如写写小巧东西活活脑筋吧!

出两个简单题目,看谁写得最短。

题目一.
用最短代码写出编印256个ASCII码的程式
ASCII就是美国标准信息交换代码,是基于拉丁字母的一套电脑编码系统(百度)
常见的0,1234...ABCDabcd..!@#$%^&也包含在内。
我写的一个用了7个bytes,未必是最短,等待你的写一个更短的,当然长些也不妨,
不同编码自有不同的逻辑技巧,他山之石可以攻玉。
图片附件: 游客没有浏览图片的权限,请 登录注册


题目二
用最短代码编印
0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
就是数字0..9 , 小写的a..z 和大写的A..Z
我写的一个用了26个bytes,或许还有优化空间!
图片附件: 游客没有浏览图片的权限,请 登录注册


想了一下,原来仍有缩小空间,这个用了24bytes

图片附件: 游客没有浏览图片的权限,请 登录注册


代码我会稍后贴出,大家来动动脑,贴出代码或结果,多交流才会进步,不是吗?

[此贴子已经被作者于2016-6-9 11:02编辑过]

搜索更多相关主题的帖子: 拉丁字母 百度 美国 技巧 
2016-06-09 09:53
Valenciax
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:11
帖 子:340
专家分:2482
注 册:2016-5-15
收藏
得分:0 
楼上两位班竹有空可以玩玩。

既然暂时没人插足,先在这里贴一个正儿八经的看看,然后一步步走下去。

程序代码:
CODE segment
assume  cs:CODE,ds:CODE,es:CODE,ss:CODE
  org 100h
start:

 mov dl,'0'

 mov ah,2

 mov cx,10
s10:

 int 21h 

 inc dl

 loop s10

 

 mov dl,'a'

 mov cx,26
s20:

 int 21h 

 inc dl

 loop s20


 mov dl,'A'

 mov cx,26
s30:

 int 21h 

 inc dl

 loop s30


 mov ah,4ch

 int 21h

CODE ENDS
END START

;39bytes

程式要小,EXE是不可行的,光PE档头就占512bytes,所以要把它变成COM格式。
COM没有档头,是直接内存的bin影像,WIN764bit以上的dos模式已经不支援运行
这些16bit程式,但仍有dosbox或模拟器可用。

COM不常见,但若要写boot起动代码,把它转换成没有档头的COM或bin是必要的。
上面这段程式编译成com,若在masm6.x
ML /AT numx.asm

若在masm5.x,步骤如下
masm numx.asm
link numx.asm
exe2bin numx.exe

好了,把编译完成,看一看,39bytes,嗯,正常写法就是这个大小。

或许有人会说,现在什么年代了,Windows都64bit,内存8G还嫌小,还在意省这么几个bytes?
我会这样回答,现在什么年代了,高铁都能跑数百里/小时,却有人喜欢踏数百公里的自行车,
苦哈哈的爬上珠穆朗玛峰,为了100公尺跑10秒内练它三五七年....

对了,就是挑战,或者游戏,写代码也可以是游戏是挑战,不当它是功课写起来起劲得多。

换一个角度看,比如我们要在一个运行中的程式插入一段代码,好不容易找到一块
50bytes的空间,你却在那里写正儿八经的标准代码,胖胖的size如下插得下那么稀缺挤逼的空间?
不想方计法把程式写得小是不行的。


回到我们这段39bytes的胖代码,如何缩小?
我们想到回圈,并把印字节改为int 10h的0Eh函数,返回dos改用int20h。

程序代码:
;31bytes
CODE segment
assume  cs:CODE,ds:CODE,es:CODE,ss:CODE
  org 100h
start:

 mov cx,10

 mov bl,2

 mov al,'0'

 mov ah,0eh
s10:

 int 10h

 inc al

 loop s10

 dec bl

 mov al,'A'

 js quit   ;-1
 jz s30

 mov al,'a'
s30:

 mov cl,26

 jmp short s10 
quit:

 int 20h

 
CODE ENDS
END START

这样一改,一下子缩小到31bytes,离姥姥家不远了。

收到的鲜花
  • hu9jj2016-06-10 08:35 送鲜花  50朵   附言:精神可嘉,支持!
  • zhulei19782016-06-10 12:37 送鲜花  50朵   附言:我很赞同
2016-06-10 08:14
Valenciax
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:11
帖 子:340
专家分:2482
注 册:2016-5-15
收藏
得分:0 
回复 5楼 wmf2014
不错,cd 20是古早dos的

[此贴子已经被作者于2016-6-10 14:57编辑过]

2016-06-10 14:32
Valenciax
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:11
帖 子:340
专家分:2482
注 册:2016-5-15
收藏
得分:0 
先谢谢wmf2014班竹也来玩儿

继续我们的缩小旅程…
回圈比标准写法复杂,似乎没有再缩小的空间,此路已走到尽头。
程式的迷宫中得找另一条捷径,我们想到资料表。

先建立一个三个资料的表格,每一项资料表示:字节,长度
就这样 buff db '0',10,'a',26,'A',26
改写程式

程序代码:
CODE segment
assume  cs:CODE,ds:CODE,es:CODE,ss:CODE
  org 100h
start:

 mov si,offset buff

 mov cx,3
S10:

 push cx

 lodsw ;读入DS:SI一个word入AX,并且SI自动加1,al=字节,ah=回圈长度
 mov cl,ah ;取回圈长度,这里ch已经=0
S20:

 mov ah,0eh

 int 10h

 inc al

 loop S20 ;内回圈
 pop cx  ;外回圈三次
 loop S10

 int 20h
buff db '0',10,'a',26,'A',26

CODE ENDS
END START


共29bytes,可以进一步缩小差距吗?
可以的,这里要借助dos的特性
特性一:
返回dos方式标准
 mov ah,4ch
 int 21h
早期的方式(不推荐)
 int 20h

另有更简单的方法:RET
程式被载内存,dos会为它保留100H作系统和程式沟通之用,
这叫PSP,PSP:0的偏移首2个BYTE是CD 20,CD 20便是INT 20H
只要CS指向PSP段,JMP 0就会跳到这道指令
而COM被载入时CS,DS,SS,ES都指向PSP段,SP指向FFFEH,栈顶处通常会是0
一通RET就弹出0值送入IP,然后跳去PSP:0,执行INT 20H

特性二:
列印字符方法有好几种,常用的
 mov dl,字符
 mov ah,2
 int 21h  ;----6 bytes

 mov al,字符
 mov ah,0eh
 int 10h  ;----也是6 bytes,但直接用al,不须经dl,在回路中应该可以减省空间
 
 其实dos另有一道后门,int 29h...快速输出字符
 mov al,字符
 int 29h

ok,把上面的程式换用这两个特性

程序代码:
CODE segment
assume  cs:CODE,ds:CODE,es:CODE,ss:CODE
  org 100h
start:

 mov si,offset buff

 mov cx,3
S10:

 push cx

 lodsw ;读入DS:SI一个word入AX,并且SI自动加1,al=字节,ah=回圈长度
 mov cl,ah ;取回圈长度,这里ch已经=0
S20:

 int 29h

 inc al

 loop S20 ;内回圈
 pop cx  ;外回圈三次
 loop S10

 ret

buff db '0',10,'a',26,'A',26

CODE ENDS
END START


26 bytes,很接近了!

顺便说说,有了dos这两个特性,题目一的7个bytes就不是什么难事了

[此贴子已经被作者于2016-6-10 14:59编辑过]

2016-06-10 14:39
Valenciax
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:11
帖 子:340
专家分:2482
注 册:2016-5-15
收藏
得分:0 
回复 8楼 wmf2014
对啊,根据经验,dos载入com/exe程式时,会把AX,BX和SI清0,但为了慎重起见,我特别写了一个程式,在刚进入程式时,记下并印出所有暂存器的值,分别在不同的dos版本测试,大致上是上面的观察结果
第1列是dosbox的结果
第2列是winxp下dos的结果
第3列是win7/32bit下dos的结果
都是AX,BX和SI清0,还有ch的值也都清0

图片附件: 游客没有浏览图片的权限,请 登录注册
2016-06-10 16:27
Valenciax
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:11
帖 子:340
专家分:2482
注 册:2016-5-15
收藏
得分:0 
上面的显示只是仿debug的做法,这是大家习惯了的观看暂存器方式,实际上dos载入程式和debug是有分别的,dos载入大概是上面的样子,我们会发现ES指向psp段(其实ds也是指向psp,不过为了指向资料段被我改变了)
因为我是这样写的
Push ax
Mov ax,data
Mov ds,ax ;ds原值被改变了
Pop ax
Call prnitREG ;印出暂存器值



Debug载入程式则不同,除了sp,一般暂存器都清0,所以有些程式若未做暂存器初始化,在debug和dos下运行,会有不同的结果



[此贴子已经被作者于2016-6-10 17:55编辑过]

2016-06-10 16:50
Valenciax
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:11
帖 子:340
专家分:2482
注 册:2016-5-15
收藏
得分:0 
回复 11楼 wmf2014
班竹不必客气,看过你写的C和JAVA的游戏,都挺不错,汇编在快和短占有优势,但写起大程式很费劲,还是高阶语言方便些
2016-06-10 18:39
Valenciax
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:11
帖 子:340
专家分:2482
注 册:2016-5-15
收藏
得分:0 
回复 13楼 AXRZ
AXRZ班竹观察是对的,但24bytes版没利用这个特性,毕竟有冒险成份,万一有dos版不把ch设0,会出现错误


下面是24 bytes版
内回圈只减ah,进一步缩到24bytes,若是加上AXRZ班竹的修改
mov ch,3,那么就是23bytes !

CODE segment
assume  cs:CODE,ds:CODE,es:CODE,ss:CODE
  org 100h
start:
 mov si,offset buff
 mov cx,3
next:
 lodsw
next1:
 int 29h
 inc al
 dec ah
 jnz next1
 loop next
next2:
 ret
buff db '0',10,'a',26,'A',26
;-------------------------------------------
CODE ENDS
END START
2016-06-11 16:31
Valenciax
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:11
帖 子:340
专家分:2482
注 册:2016-5-15
收藏
得分:0 
回复 16楼 AXRZ
哈..对的,一直被直觉左右,想不起inc al和inc ax差一个bytes
2016-06-12 07:04
快速回复:大家来写写汇编小玩意
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.016877 second(s), 11 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved