汇编源代码代码转换问题

> 问题详情
将汇编语言源程序转换成等价的目标程序的过程称为______。A.汇编B.编译C.解释D.源程序
悬赏:0&答案豆
提问人:匿名网友
发布时间:
将汇编语言源程序转换成等价的目标程序的过程称为______。A.汇编B.编译C.解释D.源程序
我有更好的答案
您可能感兴趣的试题
1在微型计算机系统中,一般有三种总线,即地址总线、控制总线和______。A.总线结构B.信息总线C.数据总线D.分类总线2下列4种设备中,属于计算机输入设备的是______。A.鼠标B.软盘C.打印机D.显示器
相关考试课程
请先输入下方的验证码查看最佳答案
图形验证:
验证码提交中……1381人阅读
汇编语言(12)
第一部分 Linux下ARM汇编语法
尽管在Linux下使用C或C++编写程序很方便,但汇编源程序用于系统最基本的初始化,如初始化堆栈指针、设置页表、操作ARM的协处理器等。初始化完成后就可以跳转到C代码执行。需要注意的是,GNU的汇编器遵循AT&T的汇编语法,可以从GNU的站点(www.gnu.org)上下载有关规范。
一. Linux汇编行结构
任何汇编行都是如下结构:
[:] [} @ comment
[:] [} @ 注释
Linux ARM 汇编中,任何以冒号结尾的标识符都被认为是一个标号,而不一定非要在一行的开始。
【例1】定义一个&add&的函数,返回两个参数的和。
.section .text, “x”
.global add @ give the symbol add external linkage
ADD r0, r0, r1& @ add input arguments
MOV pc, lr @ return from subroutine
@ end of program
二. Linux 汇编程序中的标号
标号只能由a~z,A~Z,0~9,“.”,_等字符组成。当标号为0~9的数字时为局部标号,局部标号可以重复出现,使用方法如下:
 标号f: 在引用的地方向前的标号
 标号b: 在引用的地方向后的标号
【例2】使用局部符号的例子,一段循环程序
&&& subs r0,r0,#1&&&&&&& @每次循环使r0=r0-1
&&& bne 1f&&&&&&&& @跳转到1标号去执行
局部标号代表它所在的地址,因此也可以当作变量或者函数来使用。
三. Linux汇编程序中的分段
(1).section伪操作
用户可以通过.section伪操作来自定义一个段,格式如下:
&.section section_name [, &flags&[, %type[,flag_specific_arguments]]]
每一个段以段名为开始, 以下一个段名或者文件结尾为结束。这些段都有缺省的标志(flags),连接器可以识别这些标志。(与armasm中的AREA相同)。
下面是ELF格式允许的段标志
&标志& 含义
【例3】定义段
&.section .mysection @自定义数据段,段名为 “.mysection”
&.align& 2
&.ascii& &Temp string \n\0&
(2)汇编系统预定义的段名
.text& @代码段
.data& @初始化数据段
.bss& @未初始化数据段
需要注意的是,源程序中.bss段应该在.text之前。
四. 定义入口点
汇编程序的缺省入口是 start标号,用户也可以在连接脚本文件中用ENTRY标志指明其它入口点。
【例4】定义入口点
.section.data
& initialized data here&
.section .bss
& uninitialized data here&
.section .text
.globl _start
&instruction code goes here&
五. Linux汇编程序中的宏定义
格式如下:
&.macro 宏名 参数名列表&& @伪指令.macro定义一个宏
&.endm& @.endm表示宏结束
如果宏使用参数,那么在宏体中使用该参数时添加前缀“\”。宏定义时的参数还可以使用默认值。
可以使用.exitm伪指令来退出宏。
【例5】宏定义
.macro SHIFTLEFT a, b
.if \b & 0
MOV \a, \a, ASR #-\b
MOV \a, \a, LSL #\b
六. Linux汇编程序中的常数
(1)十进制数以非0数字开头,如:123和9876;
(2)二进制数以0b开头,其中字母也可以为大写;
(3)八进制数以0开始,如:;
(4)十六进制数以0x开头,如:0xabcd,0X123f;
(5)字符串常量需要用引号括起来,中间也可以使用转义字符,如: “You are welcome!\n”;
(6)当前地址以“.”表示,在汇编程序中可以使用这个符号代表当前指令的地址;
(7)表达式:在汇编程序中的表达式可以使用常数或者数值, “-”表示取负数, “~”表示取补,“&&”表示不相等,其他的符号如:+、-、*、 /、%、&、&&、&、&&、|、&、^、!、==、&=、&=、&&、|| 跟C语言中的用法相似。
七. Linux下ARM汇编的常用伪操作
在前面已经提到过了一些为操作,还有下面一些为操作:
&& 数据定义伪操作: .byte,.short,.long,.quad,.float,.string/.asciz/.ascii,重复定义伪操作.rept,赋值语句.equ/.set ;
&& 函数的定义 ;
&& 对齐方式伪操作 .align;
&& 源文件结束伪操作.end;
&& .include伪操作;
&& if伪操作;
&& .global/ .globl 伪操作 ;
&& .type伪操作 ;
&& 列表控制语句 ;
&& 区别于gas汇编的通用伪操作,下面是ARM特有的伪操作 :.reg ,.unreq ,.code ,.thumb ,.thumb_func ,.thumb_set, .ltorg ,.pool
1. 数据定义伪操作
(1) .byte:单字节定义,如:.byte 1,2,0b01,0x34,072,'s' ;
(2) .short:定义双字节数据,如:.short 0x ;
(3) .long:定义4字节数据,如:.long 0x76565
(4) .quad:定义8字节,如:.quad 0xabcd
(5) .float:定义浮点数,如:
& .float 0f-338327\
&&& .E-40&&&&&&&&&&&&&&&& @ - pi
(6) .string/.asciz/.ascii:定义多个字符串,如:
&& .string &abcd&, &efgh&, &hello!&
&& .asciz &qwer&, &sun&, &world!&
&& .ascii &welcome\0&
需要注意的是:.ascii伪操作定义的字符串需要自行添加结尾字符'\0'。
(7) .rept:重复定义伪操作, 格式如下:
&&&&&&&&&&&&&& .rept 重复次数
&&&&&&&&&&&&&& 数据定义
&&&&&&&&&&&&&& .endr& @结束重复定义
&&&& 例如:
&&&&&&&&&&&&&&& .rept 3
&&&&&&&&&&&&&&& .byte 0x23
&&&&&&&&&&&&&&& .endr
(8) .equ/.set: 赋值语句, 格式如下:
&&&&&&&&&&&&&&& .equ(.set) 变量名,表达式
&&&& 例如:
&&&&&&&&&&&&&&& .equ abc 3& @让abc=3
2.函数的定义伪操作
(1)函数的定义,格式如下:
&&&&&&&& 函数名:
&&&&&&&& 函数体
&&&&&&&& 返回语句
一般的,函数如果需要在其他文件中调用, 需要用到.global伪操作将函数声明为全局函数。为了不至于在其他程序在调用某个C函数时发生混乱,对寄存器的使用我们需要遵循APCS准则。函数编译器将处理为函数代码为一段.global的汇编码。
(2)函数的编写应当遵循如下规则:
&& a1-a4寄存器(参数、结果或暂存寄存器,r0到r3 的同义字)以及浮点寄存器f0-f3(如果存在浮点协处理器)在函数中是不必保存的;
&& 如果函数返回一个不大于一个字大小的值,则在函数结束时应该把这个值送到 r0 中;
&& 如果函数返回一个浮点数,则在函数结束时把它放入浮点寄存器f0中;
&& 如果函数的过程改动了sp(堆栈指针,r13)、fp(框架指针,r11)、sl(堆栈限制,r10)、lr(连接寄存器,r14)、v1-v8(变量寄存器,r4 到 r11)和 f4-f7,那么函数结束时这些寄存器应当被恢复为包含在进入函数时它所持有的值。
3. .align .end .include .incbin伪操作
(1).align:用来指定数据的对齐方式,格式如下:
&&&&&&&&&&&&&&& .align [absexpr1, absexpr2]
&&&& 以某种对齐方式,在未使用的存储区域填充值. 第一个值表示对齐方式,4, 8,16或&&&& 32. 第二个表达式值表示填充的值。
(2).end:表明源文件的结束。
(3).include:可以将指定的文件在使用.include 的地方展开,一般是头文件,例如:
&&&&&&&&&&&&&&& .include “myarmasm.h”
(4).incbin伪操作可以将原封不动的一个二进制文件编译到当前文件中,使用方法如下:
&&&&&&&&&&& .incbin &file&[,skip[,count]]
&&&& skip表明是从文件开始跳过skip个字节开始读取文件,count是读取的字数.
4. .if伪操作
根据一个表达式的值来决定是否要编译下面的代码, 用.endif伪操作来表示条件判断的结束, 中间可以使用.else来决定.if的条件不满足的情况下应该编译哪一部分代码。
.if有多个变种:
&.ifdef symbol&&&&&&&&&& @判断symbol是否定义
&.ifc string1,string2&& @字符串string1和string2是否相等,字符串可以用单引号括起来
&.ifeq expression&&&&&& @判断expression的值是否为0
.ifeqs string1,string2& @判断string1和string2是否相等,字符 串必须用双引号括起来
.ifge expression&&&&&&&& @判断expression的值是否大于等于0
.ifgt absolute expression& @判断expression的值是否大于0
.ifle expression&&&&&&&& @判断expression的值是否小于等于0
.iflt absolute expression& @判断expression的值是否小于0
.ifnc string1,string2&&&& @判断string1和string2是否不相等, 其用法跟.ifc恰好相反。
.ifndef symbol, .ifnotdef symbol& @判断是否没有定义symbol,& 跟.ifdef恰好相反
.ifne expression&&&&&&&&& @如果expression的值不是0, 那么编译器将编译下面的代码
.ifnes string1,string2&&& @如果字符串string1和string2不相 等, 那么编译器将编译下面的代码.
5. .global& .type&& .title&& .list
(1).global/ .globl :用来定义一个全局的符号,格式如下:
&&&&&& .global symbol& 或者& .globl symbol
(2).type:用来指定一个符号的类型是函数类型或者是对象类型, 对象类型一般是数据, 格式如下:
&&&&&&&&&&& .type 符号, 类型描述
.type a, @object
.size a, 4
.section .text
.type asmfunc, @function
.globl asmfunc
mov pc, lr
(3)列表控制语句:
.title:用来指定汇编列表的标题,例如:
&&&&&&&&&&& .title “my program”
.list:用来输出列表文件.
6. ARM特有的伪操作
(1) .reg: 用来给寄存器赋予别名,格式如下:
&&&&&&&&&&&&&&&&&& 别名 .req 寄存器名
(2) .unreq: 用来取消一个寄存器的别名,格式如下:
       .unreq 寄存器别名
  注意被取消的别名必须事先定义过,否则编译器就会报错,这个伪操作也可以用来取消系统预制的别名, 例如r0, 但如果没有必要的话不推荐那样做。
(3) .code伪操作用来选择ARM或者Thumb指令集,格式如下:
           .code 表达式
  如果表达式的值为16则表明下面的指令为Thumb指令,如果表达式的值为32则表明下面的指令为ARM指令.
(4) .thumb伪操作等同于.code 16, 表明使用Thumb指令, 类似的.arm等同于.code 32
(5) .force_thumb伪操作用来强制目标处理器选择thumb的指令集而不管处理器是否支持
(6) .thumb_func伪操作用来指明一个函数是thumb指令集的函数
(7) .thumb_set伪操作的作用类似于.set, 可以用来给一个标志起一个别名, 比.set功能增加的一点是可以把一个标志标记为thumb函数的入口, 这点功能等同于.thumb_func
(8) .ltorg用于声明一个数据缓冲池(literal pool)的开始,它可以分配很大的空间。
(9) .pool的作用等同.ltorg
(9).space &number_of_bytes& {,&fill_byte&}
分配number_of_bytes字节的数据空间,并填充其值为fill_byte,若未指定该值,缺省填充0。(与armasm中的SPACE功能相同)
(10).word &word1& {,&word2&} …
插入一个32-bit的数据队列。(与armasm中的DCD功能相同)
可以使用.word把标识符作为常量使用
& valueOfStart:
&& .word Start
&这样程序的开头Start便被存入了内存变量valueOfStart中。
(11).hword &short1& {,&short2&} …
插入一个16-bit的数据队列。(与armasm中的DCW相同)
八. GNU ARM汇编特殊字符和语法
代码行中的注释符号: ‘@’
整行注释符号: ‘#’
语句分离符号: ‘;’
直接操作数前缀: ‘#’ 或 ‘$’
第二部分 GNU的编译器和调试工具
一. 编译工具
1.编辑工具介绍
GNU提供的编译工具包括汇编器as、C编译器gcc、C++编译器g++、连接器ld和二进制转换工具objcopy。基于ARM平台的工具分别为arm-linux-as、arm-linux-gcc、arm-linux-g++、arm- linux-ld和arm-linux- objcopy。GNU的编译器功能非常强大,共有上百个操作选项,这也是这类工具让初学者头痛的原因。不过,实际开发中只需要用到有限的几个,大部分可以采用缺省选项。GNU工具的开发流程如下:编写C、C++语言或汇编源程序,用gcc或g++生成目标文件,编写连接脚本文件,用连接器生成最终目标文件(elf格式),用二进制转换工具生成可下载的二进制代码。
(1)编写C、C++语言或汇编源程序
通常汇编源程序用于系统最基本的初始化,如初始化堆栈指针、设置页表、操作ARM的协处理器等。初始化完成后就可以跳转到C代码执行。需要注意的是,GNU的汇编器遵循AT&T的汇编语法,读者可以从GNU的站点(www.gnu.org)上下载有关规范。汇编程序的缺省入口是 start标号,用户也可以在连接脚本文件中用ENTRY标志指明其它入口点(见下文关于连接脚本的说明)。
(2)用gcc或g++生成目标文件
如果应用程序包括多个文件,就需要进行分别编译,最后用连接器连接起来。如笔者的引导程序包括3个文件:init.s(汇编代码、初始化硬件)xmrecever.c(通信模块,采用Xmode协议)和flash.c(Flash擦写模块)。
分别用如下命令生成目标文件: arm-linux-gcc-c-O2-oinit.oinit.s arm-linux-gcc-c-O2-oxmrecever.oxmrecever.c arm-linux-gcc-c-O2-oflash.oflash.c 其中-c命令表示只生成目标代码,不进行连接;-o命令指明目标文件的名称;-O2表示采用二级优化,采用优化后可使生成的代码更短,运行速度更快。如果项目包含很多文件,则需要编写makefile文件。关于makefile的内容,请感兴趣的读者参考相关资料。
(3)编写连接脚本文件
gcc 等编译器内置有缺省的连接脚本。如果采用缺省脚本,则生成的目标代码需要操作系统才能加载运行。为了能在嵌入式系统上直接运行,需要编写自己的连接脚本文件。编写连接脚本,首先要对目标文件的格式有一定了解。GNU编译器生成的目标文件缺省为elf格式。elf文件由若干段(section)组成,如不特殊指明,由C源程序生成的目标代码中包含如下段:.text(正文段)包含程序的指令代码;.data(数据段)包含固定的数据,如常量、字符串;.bss(未初始化数据段)包含未初始化的变量、数组等。C++源程序生成的目标代码中还包括.fini(析构函数代码)和.
init(构造函数代码)等。连接器的任务就是将多个目标文件的.text、.data和.bss等段连接在一起,而连接脚本文件是告诉连接器从什么地址开始放置这些段。例如连接文件link.lds为:
ENTRY(begin)
.text:{*(.text)}
.data:{*(.data)}
.bss:{*(.bss)}
其中,ENTRY(begin)指明程序的入口点为begin标号;.=0x指明目标代码的起始地址为0x,这一段地址为 MX1的片内RAM;.text:{*(.text)}表示从0x开始放置所有目标文件的代码段,随后的.data:{* (.data)}表示数据段从代码段的末尾开始,再后是.bss段。
(4)用连接器生成最终目标文件
有了连接脚本文件,如下命令可生成最终的目标文件:
arm-linux-ld –no stadlib –o bootstrap.elf -Tlink.lds init.o xmrecever.o flash.o
其中,ostadlib表示不连接系统的运行库,而是直接从begin入口;-o指明目标文件的名称;-T指明采用的连接脚本文件(也可以使用-Ttext address,address表示执行区地址);最后是需要连接的目标文件列表。
(5)生成二进制代码
连接生成的elf文件还不能直接下载执行,通过objcopy工具可生成最终的二进制文件:
arm-linux-objcopy –O binary bootstrap.elf bootstrap.bin
其中-O binary指定生成为二进制格式文件。Objcopy还可以生成S格式的文件,只需将参数换成-O srec。还可以使用-S选项,移除所有的符号信息及重定位信息。如果想将生成的目标代码反汇编,还可以用objdump工具:
&arm-linux-objdump -D bootstrap.elf
至此,所生成的目标文件就可以直接写入Flash中运行了。
2.Makefile实例
example: head.s& main.c
&arm-linux-gcc -c -o head.o head.s
&arm-linux-gcc -c -o main.o main.c
&arm-linux-ld -Tlink.lds head.o ain.o -o example.elf
&arm-linux-objcopy -O binary -S example_tmp.o example
&arm-linux-objdump -D -b binary -m arm& example &ttt.s
二. 调试工具
Linux下的GNU调试工具主要是gdb、gdbserver和kgdb。其中gdb和gdbserver可完成对目标板上Linux下应用程序的远程调试。gdbserver是一个很小的应用程序,运行于目标板上,可监控被调试进程的运行,并通过串口与上位机上的gdb通信。开发者可以通过上位机的gdb输入命令,控制目标板上进程的运行,查看内存和寄存器的内容。gdb5.1.1以后的版本加入了对ARM处理器的支持,在初始化时加入-
target==arm参数可直接生成基于ARM平台的gdbserver。gdb工具可以从ftp: //ftp.gnu.org/pub/gnu/gdb/上下载。
对于Linux内核的调试,可以采用kgdb工具,同样需要通过串口与上位机上的gdb通信,对目标板的Linux内核进行调试。可以从/projects/kgdb/上了解具体的使用方法。
参考资料:
1. Richard Blum,Professional Assembly Language
2. GNU ARM 汇编快速入门,http://blog.chinaunix.net/u/31996/showart.php?id=326146
3. ARM GNU 汇编伪指令简介,/jb8164/archive//41661.aspx
4. GNU汇编使用经验,http://blog.chinaunix.net/u1/37614/showart_390095.html
5. GNU的编译器和开发工具,/blog-htm-do-showone-uid-34335-itemid-81387-type-blog.html
6. 用GNU工具开发基于ARM的嵌入式系统,/liren0@126/blog/static//
7. objcopy命令介绍,http://blog.csdn.net/junhua198310/archive//1669545.aspx
=================================================================================
(补充)转:/760159/blog/item/122980def7c9e.html/cmtid/b6a74a48226aca4
ARM的ADS汇编器与GCC汇编器
一:ads下的一段汇编程序:
EXPORT BootReset
B resetvec_reqset
IMPORT BootEntry
IMPORT |Image$$RO$$Limit|
AREA BOOTROM, CODE, READONLY
LDR r0, =|Image$$RO$$Limit|
ldr pc, [pc,#-&F20]
转换到gcc下的汇编程序为:
.global BootReset
BootReset:
B resetvec_reqset
.extern BootEntry
.extern Image_RO_Limit
# AREA BOOTROM, CODE, READONLY
LDR r0, =Image_RO_Limit
ldr pc, [pc,#-0xF20]
二:将ARM SDT下的汇编码移植到GCC for ARM编译器时,经常要做如下修改:
1、注释行以“@”或&&代替“;”
2、伪操作符替换:
INCLUDE 替换成 .INCLUDE
TCLK2 EQU PB25 替换成 .equ TCLK2, PB25
EXPORT 替换成 .global
IMPORT 替换成 .extern
DCD 替换成 .long
IF :DEF: 替换成 .IFDEF
ELSE 替换成 .ELSE
ENDIF 替换成 .ENDIF
:OR: 替换成 |
:SHL: 替换成 &&
END 替换成 .end
符号定义后加&:&号
AREA Word, CODE, READONLY --& .text
AREA Block, DATA, READWRITE --& .data
CODE32 --& .arm
CODE16 --& .thumb
LTORG --& .ltorg
3、操作数及运算符号替换
ldr pc, [pc, #&18] 替换成 ldr pc, [pc, #+0x18]
“&”以“+0x”号替换
最近那些课比较麻烦,好长时间没做ARM了,今天拿出一段nand准备在ADS下搭建调试环境,发现两家的汇编代码有但不兼容,需要修改一下.现在罗列一下我主要修改的地方,其他很多可能没遇到,大家还是自己查一查文档吧。
如arm-linux汇编头:
.global_start
修改为ads版本:
AREA&&&&&&&&nand1,&&&&&&&&CODE,READONLY
注意AREA和ENTRY前面都有tab空格,否则编译出错。
2、修改段标志
去掉arm-linux汇编中的:号即可在ads中使用。
3、ads需要加上ENTRY和END指令表示程序入口和结束标志
4、ADS中的C语言混编
与arm-linux汇编不同,ads下的汇编调用C语言的函数时需要指定IMPORT
切记注意在IMPORT前面加tab键空格。否则可能出现下面的错误(崩溃啊...):
arm汇编的条件执行码,这个比较常用,页贴上来供自己参考:
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 转自:http://blog.chinaunix.net/uid--id-1826253.html
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& /yixiaoyang/archive//1881273.html
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:158893次
积分:2984
积分:2984
排名:第8320名
原创:101篇
转载:26篇
译文:18篇
评论:46条
(1)(1)(3)(4)(1)(1)(1)(4)(1)(6)(6)(4)(2)(3)(2)(14)(5)(8)(3)(3)(10)(3)(1)(10)(7)(11)(8)(14)(8)常见汇编代码 - 推酷
常见汇编代码
# 常见汇编代码 #
1. 编写程序:比较AX,BX,CX中带符号数的大小,将最大的数放在AX中
code segment
assume cs:code
sort: cmp ax,bx
jge X&&&&&&&&& ;如果ax大于等于bx就跟cx比较
xchg ax,bx
X:cmp ax,cx&&&&&& ;如果ax大于cx
xchg ax,cx&
mov ax,4c00h
2.要求对键盘输入的小写字母用大写字母显示出来
code segment
assume cs:code
start: mov ah,1
cmp al,'a'&&&&&&
cmp al,'z'
sub al,20h&&&&&& ;'A'~'Z':41~5AH&&&& ‘a'~'z':61~7ah
3.编写程序:从键盘上接收一个四位数的十进制数,并在终端上显示出与它等值的二进制数。
code segment
assume cs:code
begin:xor bx,bx&&&&&& ;清空bx
mov cl,4&&&&&&& ;设置内外层的循环次数
input:shl bx,cl&&&&&&& ;bx中的内容逻辑左移
int 21h&&&&&&&&& ;输入
cmp al,30h&&&&&&& ;是否小于0
jb& input&&&&&&&& ;是就重新输入
cmp al,39h&&&&&&& ;是否大于9
ja& input&&&&&
and al,0fh&&&&&&& ;转换为相应的二进制
jmp combine
combine:or bl,al&&&&&&&&
display:mov cx,16&&&&&&& ;输出的循环次数
print:mov dl,0
or dl,30h&&&&&&& ;清空dl
loop print
4.将内存ffff:0~ffff:d单元中的数据复制到0:200~0:20d单元中。
code segment
assume cs:code
mov cx,0fh
copy:mov ax,0ffffh&&&
mov dl,[bx]
mov ax,0020h
mov [bx],dl
mov ax,4c00h
code& ends
5.将AX寄存器中的16位数分成四组,每组四位,然后把这四组数分别放在AL、BL、CL和DL中。
data segment
s db 4 dup(?)&& ;占位,并清空
mov ax,0ffffh
;-----------------------------------&&&
progrnam segment
assume cs:progrnam,ds:data
begin:mov cl,4&&&& ;ax逻辑右移四次
mov ch,4&&&&
X: mov dx,ax
and dx,0fh&&&&& ;逻辑与屏蔽高位
mov [bx],dl&& ;以字节形式将dl移入bx
shr ax,cl&&&&&& ;逻辑右移
Y: mov dl,s&&&&&&& ;依次移入相应寄存器内
mov cl,s+1
mov bl,s+2
mov al,s+3
progrnam ends
6.从键盘输入一系列字符,以字符‘$’为结束符,然后对其中的非数字字符计数,并显示出计数结果。
`stack segment
dw& 100h&&& dup(?)
top& label&& word
stack ends
data segment
h1&& db& 'Please input a string: ','$'
h2&& db 'The number of the chars that is not digit:','$'
crlf& db 0dh,0ah,24h
data&& ends
code& segment
assume& cs:code,ds:data,ss:stack
main& proc&&& far
begin:mov&&&& ax,stack
mov&&&& ss,ax
lea&&&& sp,top
mov&&&& ax,data
mov&&&& ds,ax
lea&&&& dx,h1
mov&&& ah,9
int&&& 21h
mov&&&& cx,0
input:&&&& mov&&&& ah,1
int&&&& 21h
cmp&&&& al,'$'
jz&&&&& exit
cmp&&&& al,30h
jb&&&&& count
cmp&&&& al,39h
jnb&&&& count
jmp&&&& input
count:& inc&&&& cx
jmp&&&& input
exit:&& lea&&&& dx,crlf
mov&&&& ah,9
int&&&& 21h
lea&&&& dx,h2
int&&&& 21h
mov&&&& si,0
mov&&&& bl,10
mov&&&& ax,cx
mem:&&&& div&&&& bl
mov&&&& dl,ah
mov&&&& dh,0
push&&& dx
inc&&&& si
mov&&&& ah,0
cmp&&&& al,0
jnz&&&& mem
prin:&&&& pop&&&& dx
add&&&& dl,30h
mov&&&& ah,2
int&&&& 21h
dec&&&& si
cmp&&&& si,0
jnz&&&& prin
mov&&&& ah,4ch
int&&&& 21H
main&&& endp
code&&& ends
end&& begin
7.已知两个整数变量A和B,试编写完成下述操作的程序:
(1)若两个数中有一个数是奇数,则将奇数存入A中,偶数存入B中
(2)若两个数均为奇数,则两数分别加1,并存回原变量。
(3)若两个数均为偶数,则两变量不变。
code segment
assume cs:code
begin: mov ax,13
test ax,0001h&&& ;A和B是否同时为奇数或偶数
jz next&&&&&&&&&& ;是
test bx,0001h&&&
jz return&&&&&&& ;B为偶数,A为奇数,加1
exchange:mov ax,dx&&&&&&& ;A为偶数,B为奇数,交换
jmp return
next:test bx,0001h&&& ;是否同为奇数
jz return&&&&&&& ;同为偶数,不变
jmp exchange
return:ret
8.比较两个字符串string1和string2所含的字符是否相同。若相同则显示‘true’,否则显示‘false’。
data segment
string1 db 'i am a student'
string2 db 'i am a student'
string3 db 'true',0dh,0ah,'$'
string4 db 'false',0dh,0ah,'$'
;--------------------------&&&&
progrnam& segment
assume cs:progrnam,ds:data
start:push ds
mov ax,data
begin:lea si,string1
lea di,string2
mov cx,string2-string1
repe cmpsb
lea dx,string3
jmp print&&&&&&
Y:lea dx,string4
print: mov ah,9
mov ax,4c00h
progrnam ends
9.编写无溢出除法的汇编子程序 。
这里所说的除法溢出并不是指分母为0而发生溢出的情况。我们以除数为8位的情况来说明,假设我们的被除数为65535(16位的最大值)存储在AX 中,除数为1,存储在CL中,然后执行除法指令: div CL。根据上面的说法,结果都是放在AX中的,余数为0,当然这没有问题,然而商为65535要放在AL中却是放不下的,因为AL能存放的最大值只为 255,所以此时就会发生溢出。我们可以看到65535/1 = 255,这显然与我位正常的除法结果不符。
如何解决这个溢出问题
既然我们知道了问题的根源,要解 决它就不困难了。为了统一而且不发生溢出,我们可以把所有的除法的商都用32位来保存,即所有的被除数都用32位,所有的除数都用16位,所有的商都用 32位,所有的余数都用16位来保存,就可以解决这个问题,因为一个数除以一个整数后,不可能大于其之前的值。而对于8位的除法,除数和被除数的高位全用 0补全即可。为了达到这个目的,我们就不能使用默认的除法指令div了,而需要我们写代码来实现我们自定义的除法。
自定义除法: X为除数,N为被除数,H代表X的高16位,L代表X的低16位,
int(H/N)和rem(H/N)代表着H除以N的商和余数
X/N = int(H/N)* 2^16 + [rem(H/N)* 2^16+L]/N
progrnam segment
assume cs:progrnam
mov ax,0ffffh
mov cx,1&&&&&&&&&& ;初始化进行测试
begin: cmp cx,0
je return&& ;除数不能为0
div cx& ;执行H/N,商保存在ax中,余数在DX中
mov bx,把商保存
pop ax&&& ;取出低位,执行rem(H/N)*2^16+L
div cx&&& ;执行[rem(H/N)*2^16+L]/N ,商保存在ax中 ,余数在dx中
mov cx,cx保存余数
mov dx,dx中保存高位除法的商
return:ret
mov ax,4c00h
progrnam ends
10.编写一个程序,接受从键盘输入的10个十进制数字,输入回车符则停止输入,然后将这些数字加密后(用XLAT指令变换)存入内存缓冲区BUFFER。加密表为:
输入数字:0,1,2,3,4,5,6,7,8,9
密码数字:7,5,9,1,3,6,8,0,2,4
data segment
number db 7,5,9,1,3,6,8,0,2,4
buffer db 10 dup(?)
;-------------------------------------
code segment
assume cs:code,ds:data
lea bx,number
input:mov ah,1
cmp al,0dh&&& ;是否为回车符
cmp al,30h&&& ;比较是否是0~9,不是就重新输入
cmp al,39h
xlat&&&&&&&&&& ;变换进行存储
mov buffer[si],al
loop input
return:ret
data segment
number db 7,5,9,1,3,6,8,0,2,4
buffer db 10 dup(?)
;-------------------------------------
code segment
assume cs:code,ds:data
lea bx,number
input:mov ah,1
cmp al,0dh&&& ;是否为回车符
cmp al,30h&&& ;比较是否是0~9,不是就重新输入
cmp al,39h
xlat&&&&&&&&&& ;变换进行存储
mov buffer[si],al
loop input
return:ret
11.编写一个子程序嵌套结构的程序模块,分别从键盘输入姓名及8个字符的电话号码,并以一定的格式显示出来。
主程序TELIST:
A.&&& 显示提示符“INPUT& NAME:”;
B.&&& 调用子程序INPUT_NAME输入姓名;
C.&&& 显示提示符“INPUT& A& TELEPHONE& NUMBER:”;
D.&&& 调用子程序INPHONE输入电话号码;
E.&&& 调用子程序PRINTLINE显示姓名及电话号码。
子程序INPUT_NAME:
A.&&& 调用键盘输入子程序GETCHAR,把输入的姓名存放在INBUF缓冲区中;
B.&&& 把INBUF中的姓名移入输出行OUTNAME。
子程序INPHONE:
A.&&& 调用键盘输入子程序GETCHAR,把输入的8位电话号码存放在INBUF缓冲区中;
B.&&& 把INBUF中的号码移入输出行OUTPHONE。
子程序PRINTLINE:
显示姓名及电话号码,格式为:
NAME&&& TEL.
X X X&&&&&&& XXXXXXXX
代码如下:
data segment
tipname db 'input name:','$'
tipnumber db 'input a telephone number:','$'
inbuf db 12 dup(' ')
crlf db 0dh,0ah,'$'
outname db 16 dup(' ')
outphone db 12 dup(' '),0dh,0ah,'$'
info db 'name',12 dup(' '),'tel',0dh,0ah,'$'
;------------------------------------
stack segment
dw 100 dup(?)&&&&& ;伪定义使得同一个变量具有不同的属性
string label word&&&
stack ends
;----------------------------------------
progrnam segment
main proc far
assume cs:progrnam,ds:data,es:data,ss:stack
start:mov ax,stack
mov sp,offset string
mov ax,data
begin:&&&&&&&&&&&&&&&
mov ah,09&&&&&&&&& ;输出提示字符串
mov dx,seg tipname
mov dx,offset tipname
call input_name&&& ;输入姓名
mov ah,09&&&&&&&&&& ;输出提示字符串
mov dx,seg tipnumber
mov dx,offset tipnumber
call input_number
call printline&&&&&
;------------------------------------------
input_name proc near
call getchar
lea si,inbuf
lea di,outname
mov cx,12&&&&& ;设置计数器
cld&&&&&&&&&&&& ;设置方向为自增
;movsb 与rep结合是传送字节,相当于 movs es:byte ptr[di],ds:[si]
rep movsb&&&&&&
input_name endp
;-----------------------------------------------
input_number proc near
call getchar
lea si,inbuf
lea di,outphone
input_number endp
;------------------------------------------------
getchar proc near
mov al,20h
mov cx,12&
lea di,inbuf
;stosb这里是为了每一次输入一个字节存入相应的缓冲区
input:mov ah,1
cmp al,0dh
mov inbuf[di],al
loop input
return: call disp_crlf&&&&&&&&&& ;输出回车符
getchar endp
;--------------------------------------
printline proc near&&&&&&&&&&&& ;这里均是将所得的字符串进行输出
mov dx,seg info
mov dx,offset info
mov dx,seg outname
mov dx,offset outname
printline endp
;---------------------------------------
disp_crlf proc near
mov dx,seg crlf
mov dx,offset crlf
disp_crlf endp
;-----------------------------------------
progrnam ends
12.试编写一个汇编语言子程序,要求将包含任意字符、以0结尾的字符串中的小写字母转换成大写字母。
data segment
string db 'i am A stuDEnt',0h
;------------------------------
progrnam segment
assume ds:data,cs:progrnam
start:push ds
xor ax,ax&&&&&
mov ax,data&
lea si,string
push si&&&&&
begin: mov al,[si]&&&&& ;判断是否为小写字母并进行转换
je return&&&&&
cmp& al,'a'
cmp& al,'z'
ja print&&&&&&&&&& ;如果不是小写字母直接进行输出
sub al,20h
mov [si],al
print:push ds&&&&&&&&&& ;将字母进行输出
;mov al,[si]
pop ds&&&&&&
jmp begin&&&&&
mov ax,4c00h
progrnam ends
end start&
13.编写程序,将一个包含有20个数据的数组M分成两个数组:正数数组P和负数数组N,并分别把这两个数组中数据的个数显示出来。&&&
data segment
string1 db 0dh,0ah, 'positive number:','$'
string2 db 0dh,0ah,'negative number:','$'
array dw& 1,2,3,4,5,6,7,8,-4,-8,-9,-6,-2,-8,8,12,18,-12,5,64
array1 dw 20 dup(?)&&&& ;存储正数数组
array2 dw 20 dup(?)&&&&& ;存储负数数组
count1 db 0
count2 db 0&&&&&&&&&&&&&& ;计数
CRLF DB 0dh,0ah,'$'
;----------------------------------
progrnam segment
main proc far
assume ds:data,cs:progrnam
s:&& push ds
mov ax,data
mov ds,ax&&&
begin:mov cx,20&&&&&&&& ;循环次数
lea bx,array&&&&& ;bx相当于数组的首地址
lea si,array1
lea di,array2&
start:mov ax,[bx]
cmp ax,0&&&&&&&& ;是否为负数
js Y&&&&&&&&&&&& ;是负数
mov [si],ax&&&&&& ;存入正数数组
inc count1
jmp short next&
Y:& mov [di],ax
inc count2
next:add bx,2
loop start
lea dx,string1
mov al,count1
call print
lea dx,string2
mov al,count2&&&&&&&&
call print
main endp&&&&&&&&&
;--------------------------------------
print& proc near
push ax&&&&& ;al中存储计数值,要进行保存
pop ax&&&&&&& ;出栈,进行ASCII码调整
aam&&&&&&&&&&& ;调整方式AH&-AL/10(商),AL&-AL%10
add ah,30h&&& ;变为0~9的ASCII码
add al,30h
lea dx,CRLF
print endp
progrnam ends
14.设有10个学生的成绩分别是76,69,84,90,73,88,99,63,100和80分。试编制一个子程序统计60~69分,70~79分,80~89分,90~99分和100分的人数,分别存放到S6,S7,S8,S9和S10单元中。
data segment
grade dw 76,69,84,90,73,88,99,63,100,80
count1 dw 0
count2 dw 0
count3 dw 0
count4 dw 0
count5 dw 0
;-----------------------------------------
progrnam segment
assume ds:data,cs:progrnam
mov ax,data
begin:mov cx,10
next:mov ax,grade[si]
sal bx,1&&& ;将(grade/10-6)&2就是
inc count1[bx]& ;count1是首地址
progrnam ends
15.输出空行
progrnam segment
assume cs:progrnam
begin:push cx
mov ax,3&&& ;这里对ax进行赋值,观察输出的结果
print:mov dl,0dh
mov ah,2&&& ;这是对与输出一个字符的bios的调用
int 21h& ;print的功能就是输出空行,0dh为回车
mov dl,00ah为换行
int 21h&&&
loop print
;这一段程序是为了测试输出后的结果,主要母的是输出一个黄色的'*'
mov al,'*'
mov bl,0eh
progrnam ends
已发表评论数()
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
主题不准确
没有分页内容
图片无法显示
视频无法显示
与原文不一致}

我要回帖

更多关于 汇编源代码 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信