×

汇编语言实例经典 错误

汇编语言实例经典(汇编指令 mov word ptr ds:[0],ss:[0] 哪里错了为什么提示 错误的数据类型)

admin admin 发表于2024-09-06 20:35:27 浏览9 评论0

抢沙发发表评论

大家好,汇编语言实例经典相信很多的网友都不是很明白,包括汇编指令 mov word ptr ds:[0],ss:[0] 哪里错了为什么提示 错误的数据类型也是一样,不过没有关系,接下来就来为大家分享关于汇编语言实例经典和汇编指令 mov word ptr ds:[0],ss:[0] 哪里错了为什么提示 错误的数据类型的一些知识点,大家可以关注收藏,免得下次来找不到哦,下面我们开始吧!

本文目录

汇编指令 mov word ptr ds:[0],ss:[0] 哪里错了为什么提示 错误的数据类型

在 Visual C++ 中使用内联汇编- -使用内联汇编可以在 C/C++ 代码中嵌入汇编语言指令,而且不需要额外的汇编和连接步骤。在 Visual C++ 中,内联汇编是内置的编译器,因此不需要配置诸如 MASM 一类的独立汇编工具。这里,我们就以 Visual Studio .NET 2003 为背景,介绍在 Visual C++ 中使用内联汇的相关知识(如果是早期的版本,可能会有些许出入)。 内联汇编代码可以使用 C/C++ 变量和函数,因此它能非常容易地整合到 C/C++ 代码中。它能做一些对于单独使用 C/C++ 来说非常笨重或不可能完成的任务。一、 优点 使用内联汇编可以在 C/C++ 代码中嵌入汇编语言指令,而且不需要额外的汇编和连接步骤。在 Visual C++ 中,内联汇编是内置的编译器,因此不需要配置诸如 MASM 一类的独立汇编工具。这里,我们就以 Visual Studio .NET 2003 为背景,介绍在 Visual C++ 中使用内联汇的相关知识(如果是早期的版本,可能会有些许出入)。 内联汇编代码可以使用 C/C++ 变量和函数,因此它能非常容易地整合到 C/C++ 代码中。它能做一些对于单独使用 C/C++ 来说非常笨重或不可能完成的任务。 内联汇编的用途包括: 使用汇编语言编写特定的函数; 编写对速度要求非常较高的代码; 在设备驱动程序中直接访问硬件; 编写 naked 函数的初始化和结束代码。二、 关键字 使用内联汇编要用到 __asm 关键字,它可以出现在任何允许 C/C++ 语句出现的地方。我们来看一些例子: 简单的 __asm 块: __asm { MOV AL, 2 MOV DX, 0xD007 OUT AL, DX }在每条汇编指令之前加 __asm 关键字: __asm MOV AL, 2 __asm MOV DX, 0xD007 __asm OUT AL, DX因为 __asm 关键字是语句分隔符,所以可以把多条汇编指令放在同一行: __asm MOV AL, 2 __asm MOV DX, 0xD007 __asm OUT AL, DX 显然,第一种方法与 C/C++ 的风格很一致,并且把汇编代码和 C/C++ 代码清楚地分开,还避免了重复输入 __asm 关键字,因此推荐使用第一种方法。 不像在 C/C++ 中的"{ }",__asm 块的"{ }"不会影响 C/C++ 变量的作用范围。同时,__asm 块可以嵌套,而且嵌套也不会影响变量的作用范围。 为了与低版本的 Visual C++ 兼容,_asm 和 __asm 具有相同的意义。另外,Visual C++ 支持标准 C++ 的 asm 关键字,但是它不会生成任何指令,它的作用仅限于使编译器不会出现编译错误。要使用内联汇编,必须使用 __asm 而不是 asm 关键字。三、 汇编语言1. 指令集 内联汇编支持 Intel Pentium 4 和 AMD Athlon 的所有指令。更多其它处理器的指令可以通过 _EMIT 伪指令来创建(_EMIT 伪指令说明见下文)。2. MASM 表达式 在内联汇编代码中,可以使用所有的 MASM 表达式(MASM 表达式是指用来计算一个数值或一个地址的操作符和操作数的组合)。3. 数据指示符和操作符 虽然 __asm 块中允许使用 C/C++ 的数据类型和对象,但它不能使用 MASM 指示符和操作符来定义数据对象。这里特别指出,__asm 块中不允许 MASM 中的定义指示符(DB、DW、DD、DQ、DT 和 DF),也不允许使用 DUP 和 THIS 操作符。MASM 中的结构和记录也不再有效,内联汇编不接受 STRUC、RECORD、WIDTH 或者 MASK。4. EVEN 和 ALIGN 指示符 尽管内联汇编不支持大多数 MASM 指示符,但它支持 EVEN 和 ALIGN。当需要的时候,这些指示符在汇编代码里面加入 NOP 指令(空操作)使标号对齐到特定边界。这样可以使某些处理器取指令时具有更高的效率。5. MASM 宏指示符 内联汇编不是宏汇编,不能使用 MASM 宏指示符(MACRO、REPT、IRC、IRP 和 ENDM)和宏操作符(《》、!、&、% 和 .TYPE)。6. 段 必须使用寄存器而不是名称来指明段(段名称"_TEXT"是无效的)。并且,段跨越必须显式地说明,如 ES:。7. 类型和变量大小 在内联汇编中,可以用 LENGTH、SIZE 和 TYPE 来获取 C/C++ 变量和类型的大大小。 * LENGTH 操作符用来取得 C/C++ 中数组的元素个数(如果不是一个数组,则结果为 1)。 * SIZE 操作符可以获取 C/C++ 变量的大小(一个变量的大小是 LENGTH 和 TYPE 的乘积)。 * TYPE 操作符可以返回 C/C++ 类型和变量的大小(如果变量是一个数组,它得到的是数组中单个元素的大小)。 例如,程序中定义了一个 8 维的整数型变量: int iArray; 下面是 C 和汇编表达式中得到的 iArray 及其元素的相关值: __asm C Size LENGTH iArray sizeof(iArray)/sizeof(iArray) 8 SIZE iArray sizeof(iArray) 32 TYPE iArray sizeof(iArray) 48. 注释 内联汇编中可以使用汇编语言的注释,即";"。例如: __asm MOV EAX, OFFSET pbBuff ; Load address of pbBuff 因为 C/C++ 宏将会展开到一个逻辑行中,为了避免在宏中使用汇编语言注释带来的混乱,内联汇编也允许使用 C/C++ 风格的注释。9. _EMIT 伪指令 _EMIT 伪指令相当于 MASM 中的 DB,但是 _EMIT 一次只能在当前代码段(.text 段)中定义一个字节。例如: __asm { JMP _CodeLabel _EMIT 0x00 ; 定义混合在代码段的数据 _EMIT 0x01 _CodeLabel: ; 这里是代码 _EMIT 0x90 ; NOP指令 }10. 寄存器使用 一般来说,不能假定某个寄存器在 __asm 块开始的时候有已知的值。寄存器的值将不能保证会从 __asm 块保留到另外一个 __asm 块中。 如果一个函数声明为 __fastcall 调用方式,则其参数将通过寄存器而不是堆栈来传递。这将会使 __asm 块产生问题,因为函数无法被告知哪个参数在哪个寄存器中。如果函数接收了 EAX 中的参数并立即储存一个值到 EAX 中的话,原来的参数将丢失掉。另外,在所有声明为 __fastcall 的函数中,ECX 寄存器是必须一直保留的。为了避免以上的冲突,包含 __asm 块的函数不要声明为 __fastcall 调用方式。 提示:如果使用 EAX、EBX、ECX、EDX、ESI 和 EDI 寄存器,你不需要保存它。但如果你用到了 DS、SS、SP、BP 和标志寄存器,那就应该用 PUSH 保存这些寄存器。 提示:如果程序中改变了用于 STD 和 CLD 的方向标志,必须将其恢复到原来的值。四、 使用 C/C++ 元素1. 可用的 C/C++ 元素 C/C++ 与汇编语言可以混合使用,在内联汇编中可以使用 C/C++ 变量以及很多其它的 C/C++ 元素,包括:符号,包括标号、变量和函数名; 常量,包括符号常量和枚举型成员; 宏定义和预处理指示符; 注释,包括"/**/"和"//"; 类型名,包括所有 MASM 中合法的类型; typedef 名称,通常使用 PTR 和 TYPE 操作符,或者使用指定的的结构或枚举成员。 在内联汇编中,可以使用 C/C++ 或汇编语言的基数计数法。例如,0x100 和 100H 是相等的。2. 操作符使用 内联汇编中不能使用诸如"《《"一类的 C/C++ 操作符。但是,C/C++ 和 MASM 共有的操作符(比如"*"和""操作符),都被认为是汇编语言的操作符,是可以使用的。举个例子: int iArray; __asm MOV iArray, BX ; Store BX at iArray + 6 (Not scaled) iArray = 0; // Store 0 at iArray+12 (Scaled) 提示:在内联汇编中,可以使用 TYPE 操作符使其与 C/C++ 一致。比如,下面两条语句是一样的: __asm MOV iArray, 0 ; Store 0 at iArray + 12 iArray = 0; // Store 0 at iArray + 123. C/C++ 符号使用 在 __asm 块中可以引用所有在作用范围内的 C/C++ 符号,包括变量名称、函数名称和标号。但是不能访问 C++ 类的成员函数。 下面是在内联汇编中使用 C/C++ 符号的一些限制:每条汇编语句只能包含一个 C/C++ 符号。在一条汇编指令中,多个符号只能出现在 LENGTH、TYPE 或 SIZE 表达式中。 在 __asm 块中引用函数必须先声明。否则,编译器将不能区别 __asm 块中的函数名和标号。 在 __asm 块中不能使用对于 MASM 来说是保留字的 C/C++ 符号(不区分大小写)。MASM 保留字包含指令名称(如 PUSH)和寄存器名称(如 ESI)等。 在 __asm 块中不能识别结构和联合标签。4. 访问 C/C++ 中的数据 内联汇编的一个非常大的方便之处是它可以使用名称来引用 C/C++ 变量。例如,如果 C/C++ 变量 iVar 在作用范围内: __asm MOV EAX, iVar ; Stores the value of iVar in EAX 如果 C/C++ 中的类、结构或者枚举成员具有唯一的名称,则在 __asm 块中可以只通过成员名称来访问(省略"."操作符之前的变量名或 typedef 名称)。然而,如果成员不是唯一的,你必须在"."操作符之前加上变量名或 typedef 名称。例如,下面的两个结构都具有 SameName 这个成员变量: struct FIRST_TYPE { char *pszWeasel; int SameName; }; struct SECOND_TYPE { int iWonton; long SameName; }; 如果按下面方式声明变量: struct FIRST_TYPE ftTest; struct SECOND_TYPE stTemp; 那么,所有引用 SameName 成员的地方都必须使用变量名,因为 SameName 不是唯一的。另外,由于上面的 pszWeasel 变量具有唯一的名称,你可以仅仅使用它的成员名称来引用它: __asm { MOV EBX, OFFSET ftTest MOV ECX, ftTest.SameName ; 必须使用"ftTest" MOV ESI, . pszWeasel ; 可以省略"ftTest" }提示:省略变量名仅仅是为了书写代码方便,生成的汇编指令还是一样的。5. 用内联汇编写函数 如果用内联汇编写函数的话,要传递参数和返回一个值都是非常容易的。看下面的例子,比较一下用独立汇编和内联汇编写的函数: ; PowerAsm.asm ; Compute the power of an integer PUBLIC GetPowerAsm _TEXT SEGMENT WORD PUBLIC ’CODE’ GetPowerAsm PROC PUSH EBP ; Save EBP MOV EBP, ESP ; Move ESP into EBP so we can refer ; to arguments on the stack MOV EAX, ; Get first argument MOV ECX, ; Get second argument SHL EAX, CL ; EAX = EAX * (2 ^ CL) POP EBP ; Restore EBP RET ; Return with sum in EAX GetPowerAsm ENDP _TEXT ENDS END C/C++ 函数一般用堆栈来传递参数,所以上面的函数中需要通过堆栈位置来访问它的参数(在 MASM 或其它一些汇编工具中,也允许通过名称来访问堆栈参数和局部堆栈变量)。 下面的程序是使用内联汇编写的: // PowerC.c #include int GetPowerC(int iNum, int iPower); int main() { printf("3 times 2 to the power of 5 is %d\n", GetPowerC( 3, 5)); } int GetPowerC(int iNum, int iPower) { __asm { MOV EAX, iNum ; Get first argument MOV ECX, iPower ; Get second argument SHL EAX, CL ; EAX = EAX * (2 to the power of CL) } // Return with result in EAX } 使用内联汇编写的 GetPowerC 函数可以通过参数名称来引用它的参数。由于 GetPowerC 函数没有执行 C 的 return 语句,所以编译器会给出一个警告信息,我们可以通过 #pragma warning 禁止生成这个警告。 内联汇编的其中一个用途是编写 naked 函数的初始化和结束代码。对于一般的函数,编译器会自动帮我们生成函数的初始化(构建参数指针和分配局部变量等)和结束代码(平衡堆栈和返回一个值等)。使用内联汇编,我们可以自己编写干干净净的函数。当然,此时我们必须自己动手做一些有关函数初始化和扫尾的工作。例如: void __declspec(naked) MyNakedFunction() { // Naked functions must provide their own prolog. __asm { PUSH EBP MOV ESP, EBP SUB ESP, __LOCAL_SIZE } . . . // And we must provide epilog. __asm { POP EBP RET } }6. 调用 C/C++ 函数 内联汇编中调用声明为 __cdecl 方式(默认)的 C/C++ 函数必须由调用者清除参数堆栈,下面是一个调用 C/C++ 函数例子: #include char szFormat = "%s %s\n"; char szHello = "Hello"; char szWorld = " world"; void main() { __asm { MOV EAX, OFFSET szWorld PUSH EAX MOV EAX, OFFSET szHello PUSH EAX MOV EAX, OFFSET szFormat PUSH EAX CALL printf // 压入了 3 个参数在堆栈中,调用函数之后要调整堆栈 ADD ESP, 12 } }提示:参数是按从右往左的顺序压入堆栈的。 如果调用 __stdcall 方式的函数,则不需要自己清除堆栈。因为这种函数的返回指令是 RET n,会自动清除堆栈。大多数 Windows API 函数均为 __stdcall 调用方式(仅除 wsprintf 等几个之外),下面是一个调用 MessageBox 函数的例子: #include TCHAR g_tszAppName = TEXT("API Test"); void main() { TCHAR tszHello = TEXT("Hello, world!"); __asm { PUSH MB_OK OR MB_ICONINFORMATION PUSH OFFSET g_tszAppName ; 全局变量用 OFFSET LEA EAX, tszHello ; 局部变量用 LEA PUSH EAX PUSH 0 CALL DWORD PTR ; 注意这里不是 CALL MessageBox,而是调用重定位过的函数地址 } }提示:可以不受限制地访问 C++ 成员变量,但是不能访问 C++ 的成员函数。7. 定义 __asm 块为 C/C++ 宏 使用 C/C++ 宏可以方便地把汇编代码插入到源代码中。但是这其中需要额外地注意,因为宏将会扩展到一个逻辑行中。为了不会出现问题,请按以下规则编写宏: 使用花括号把 __asm 块包围住; 把 __asm 关键字放在每条汇编指令之前; 使用经典 C 风格的注释("/* comment */"),不要使用汇编风格的注释("; comment")或单行的 C/C++ 注释("// comment"); 举个例子,下面定义了一个简单的宏: #define PORTIO __asm \ /* Port output */ \ { \ __asm MOV AL, 2 \ __asm MOV DX, 0xD007 \ __asm OUT DX, AL \ } 乍一看来,后面的三个 __asm 关键字好像是多余的。其实它们是需要的,因为宏将被扩展到一个单行中: __asm /* Port output */ { __asm MOV AL, 2 __asm MOV DX, 0xD007 __asm OUT DX, AL } 从扩展后的代码中可以看出,第三个和第四个 __asm 关键字是必须的(作为语句分隔符)。在 __asm 块中,只有 __asm 关键字和换行符会被认为是语句分隔符,又因为定义为宏的一个语句块会被认为是一个逻辑行,所以必须在每条指令之前使用 __asm 关键字。 括号也是需要的,如果省略了它,编译器将不知道汇编代码在哪里结束,__asm 块后面的 C/C++ 语句看起来会被认为是汇编指令。 同样是由于宏展开的原因,汇编风格的注释("; comment")和单行的 C/C++ 注释("// commen")也可能会出现错误。为了避免这些错误,在定义 __asm 块为宏时请使用经典 C 风格的注释("/* comment */")。 和 C/C++ 宏一样 __asm 块写的宏也可以拥有参数。和 C/C++ 宏不一样的是,__asm 宏不能返回一个值,因此,不能使用这种宏作为 C/C++ 表达式。 不要不加选择地调用这种类型的宏。比如,在声明为 __fastcall 的函数中调用汇编语言宏可能会导致不可预料的结果(请参看前文的说明)。8. 转跳 可以在 C/C++ 里面使用 goto 转跳到 __asm 块中的标号处,也可以在 __asm 块中转跳到 __asm 块里面或外面的标号处。__asm 块内的标号是不区分大小写的(指令、指示符等也是不区分大小写的)。例如: void MyFunction() { goto C_Dest; /* 正确 */ goto c_dest; /* 错误 */ goto A_Dest; /* 正确 */ goto a_dest; /* 正确 */ __asm { JMP C_Dest ; 正确 JMP c_dest ; 错误 JMP A_Dest ; 正确 JMP a_dest ; 正确 a_dest: ; __asm 标号 } C_Dest: /* C/C++ 标号 */ return; } 不要使用函数名称当作标号,否则将转跳到函数中执行,而不是标号处。例如,由于 exit 是 C/C++ 的函数,下面的转跳将不会到 exit 标号处: ; 错误:使用函数名作为标号 JNE exit . . . exit: . . . 美元符号"$"用于指定当前指令位置,常用于条件跳转中,例如: JNE $+5 ; 下面这条指令的长度是 5 个字节 JMP _Label NOP ; $+5,转跳到了这里 . . . _Label: . . .五、在 Visual C++ 工程中使用独立汇编 内联汇编代码不易于移植,如果你的程序打算在不同类型的机器(比如 x86 和 Alpha)上运行,你可能需要在不同的模块中使用特定的机器代码。这时候你可以使用 MASM(Microsoft Macro Assembler),因为 MASM 支持更多方便的宏指令和数据指示符。 这里简单介绍一下在 Visual Studio .NET 2003 中调用 MASM 编译独立汇编文件的步骤。 在 Visual C++ 工程中,添加按 MASM 的要求编写的 .asm 文件。在解决方案资源管理器中,右击这个文件,选择"属性"菜单项,在属性对话框中,点击"自定义生成步骤",设置如下项目: 命令行:ML.exe /nologo /c /coff "-Fo$(IntDir)\$(InputName).obj" "$(InputPath)" 输出:$(IntDir)\$(InputName).obj 如果要生成调试信息,可以在命令行中加入"/Zi"参数,还可以根据需要生成 .lst 和 .sbr 文件。***隐藏网址***

高分求助在线等:将2个汇编程序合成一个

在编写和调试C6000程序时,为了使C6000代码获得最好的性能,我们需要按照软件编程的3个阶段进行,每个阶段完成的任务如下: 第一阶段:开始可以不考虑C6000的有关知识,完全根据任务编写C语言程序。在CCS环境下用C6000的代码产生工具,编译产生在C6000内运行的代码,证明其功能正确。然后再用CCS的调试工具,如debug和profiler等,分析确定代码可能存在的、影响性能的低效率段。为进一步改进代码性能,需要进入第二阶段。 第二阶段:利用内联函数、CCS编译选项和其他具体优化方法改进C语言程序。重复第一阶段,检查所产生的C6000代码性能。如果产生的代码仍不能达到所期望的性能,则进入第三阶段。 第三阶段:从C语言程序中抽出对性能影响很大的程序段,用线性汇编重新编写,再用汇编优化器优化,链接,直到达到所期望的性能要求。 具体到G.729A标准编解码器的实时要求,第三阶段是工作的重点,而且线性汇编的重新编写要求对程序代码和DSP的特性有充分的了解。 3. G.729A代码的剖析 CCS集成开发环境为软件开发人员提供了高效的开发、调试工具。特别是它提供了评价器( profiler)的优化工具,通过收集在指定代码区间程序执行的统计性能,分析确定程序中各个段、各个子函数所花费的处理器时间,从而把程序的优化集中在对程序性能影响最大的代码段上去。其两种不同的测试方法是: (1) 在需要测定复杂度的程序段的开头和结尾处设定两个断点,打开时钟窗口,运行程序。在第一个断点处执行停止,这时双击时钟窗口使之清0,接着继续执行程序,在第二个断点处停止,这时,时钟窗口显示的值便是该段代码的复杂度。这在测试程序中一个函数的复杂度是非常有用的。 (2) 先打开统计窗口,在需要测试的程序段头尾设置统计点((Probe Point)。程序运行结束后,统计窗口内该程序段后面的统计值便是该代码段的复杂度。这种方法较简单,统计点自动收集统计信息,无需手工干涉,这在测定程序多段代码的复杂度是非常有用。 4. 线性汇编的优化 线性汇编是TI提供的一种汇编语言,其指令系统和汇编语言的指令系统完全相同,但在编写时不需要指定寄存器和操作单元,也不需要考虑延时的问题,因此编写线性汇编相对要容易一些 。 经过第一阶段和第二阶段的优化后,音频编码程序在DM642上的运行状况有了很大改善,但是经测试仍然没有到达实时效果,而高级语言的效率几乎发挥到了极致,测试的速度达到了36.5帧/s,是未优化之前的10倍。这时,我们采用线性汇编语言重新编写C代码的低效率段程序,进一步提高程序的执行效率和充分利用DM642的硬件资源,最终按设计要求在DM642实时实现G.729A编码。在前面的DSP开发流程已经提过,DSP开发的最后一个手段是用汇编重写C代码,它是唯一可以既提高程序执行速度又可以减少程序体积的方法。由于针对并行处理器编写汇编的难度很大,一般采取的是混合编程的方法,即程序的主要部分用C代码,部分耗时较大的函数可以用线性汇编改写。 在编写线性汇编优化代码的过程中,为了提高代码执行效率,我们需要遵循以下原则: (1)写并行代码:通过使用汇编指令并行执行的方法减少循环内的执行周期数,优化线性汇编代码。这里的关键问题是弄清指令相关性,只有不相关的指令才能并行执行。辨别指令是否相关,可以使用相关图。 (2)处理跳转指令和转移指令:汇编程序的一大特点就是频繁地跳转,当满足不同的条件时,要求程序进行不同的操作,或跳到相应的位置。对于“大于”、“大于等于”、“小于”、“小于等于”等较为接近的逻辑判断和处理,应慎重对待,否则将产生逻辑性错误,并且很难调试。当发生溢出需进行相应处理时,这种现象尤为突出。 (3)尽量减少循环体内的指令数:G.729A的算法实现,有许多是在循环内部完成的,有些地方如固定码本搜索过程中,为了确定四个非0脉冲的位置和幅度,还用到了多重循环。在循环内部,特别是在嵌套较深的循环内部,减少一条指令可以大大降低程序的操作次数。例如,对于一个每重循环8次的四重嵌套循环,在最内层循环每减少一条指令,整个程序可以少执行84=4096语句。因此在设计程序时,能够放在循环体外执行的语句,尽量放在循环体外执行。 (4)展开程序体:在一定条件下,尽量展开程序,以减少子程序的调用和返回次数,牺牲空间换取时间。 G.729A算法中的LPC模块、LSP量化及激励码本搜索耗时最多,为进一步提高代码效率,对相关计算、FIR滤波等部分函数用线性汇编语言进行了改写,并用画相关图等方法有针对性的进行优化。经汇编优化器优化后,代码效率比C语言直接编译有明显提高。 5. 优化工作的创新点 在对G.729A的优化中,本文在前人研究成果的基础上,针对TMS320DM642 DSP系列芯片提出了一些有价值的新方法。这些创新点在不同程度上提高了代码的优化速度和执行效率,在语音编解码的DSP实时实现中起到了关键性作用。下面,以举例的方式阐明一些经典的方法。 5.1 绘制分析图,掌握函数结构 对于一个语句较多、结构复杂的函数,为了充分了解其逻辑结构和语句的相关性,我们通常采用画分析图的方法。分析图的形式比较灵活,可以根据具体的情况选用不同的制图工具。在编写线性汇编的时候,需要考虑存取数组中的元素,数据打包操作和数据相关性等问题,分析图有助于正确处理这些问题。 在对函数Cor_h_X( )优化过程中,我们遇到了一定的困难,原因在于其中有一个双层的循环体,内层的次数与外层有关,外层的循环次数为40,并且循环内部的语句有先后的相关性。这样的结构如果用循环展开的方法将会用到大量的寄存器,数目超出了64个,需要开辟额外的内存空间去存放临时变量,而读写内存会消耗较多的时间,因此这样执行效率不会有充分的提高。对此,我们利用分析图描述了函数中关键代码的数组X的使用情况,如图1所示:图1 cor_h_X( )函数分析图(部分) 图1直观地反映了数组16位h的元素),这样就可节省寄存器的使用个数,免去了开辟内存空间和中间变量的存取指令。 对于函数cor_h_X( ),利用上述思想编写线性汇编,只需要定义57个寄存器就可以完成所用的操作,存取指令从1760条优化到30条,仅为原来的1/60。同时执行速度从390072个时钟减少到35871个,降为原来的1/10。 绘制的分析图可以包含相关图,相关表等,使资源安排更加合理。该方法在其他函数的改写中也多次使用到。 5.2 功能相似的函数或代码段合并为一个函数 线性汇编在提高代码效率的同时也成倍的增加了代码尺寸,以上述cor_h_X( )为例,它在该写后代码尺寸从660条增大到7776条(该数据由CCS剖析工具分析所得)。在工程应用中,对于有限的内存程序区,我们会适当减少程序占用的空间。合并功能相似的函数可以达到这一要求。 在LSP量化处理中,源代码中给出了2个LSP选择函数:Lsp_select_1( )和Lsp_select_2( ),而我们发现它们具有相同的功能和相似的结构,因此,在对两者的线性汇编改写中,我们只需编写一个函数(命名为Lsp_select)即可实现LSP量化处理中这两个模块的功能。 另外,在对于一些数组拷贝,数组初始化的代码,我们同样可以用此方法,编写一个函数实现,这样可以在提高执行效率的同时,减少程序占用的内存空间。 5.3 多个循环合并为一个循环 C代码改写线性汇编的时候,我们常常会发现,只要作一些调整,两个或多个循环完成的操作完全可以由一个循环来完成。以LPC子模块240点加窗语音的自相关计算Autocorr()函数为例,经过优化改写的C代码(部分)如下: for(i=0; i《L_WINDOW; i++) //第一个循环体 y)+0x00008000L)》》16; sum = 1; //避免为0的情况 for(i=0; i《L_WINDOW; i++) //第二个循环体 sum = _sadd(sum,_smpy(y)); 这段代码包含了两个for循环,在CCS中直接编译运行并行度很差,利用线性汇编重写代码。我们发现两个循环体的循环次数均为60(L_WINDOW=60),所处理的数组不同,并且两个循环没有相关性,可以把第一和第二个循环合并成一个循环。前者的功能是对语音信号进行加窗;后者是实现乘累加(Mac)。两者合并后采用线性汇编编写,其代码如下: mvk 60,i //设置循环次数 loop1: lddw *ham++,hamih:hamil //hamwindow指针 lddw *x++,xih:xil //x指针 smpy2 hamil,xil,yi1:yi0 //两对16位操作数相承,并行执行 smpy2 hamih,xih,yi3:yi2 sadd yi0,con0x8000,yi0 sadd yi1,con0x8000,yi1 sadd yi2,con0x8000,yi2 sadd yi3,con0x8000,yi3 packh3 yi1,yi0,yl //数据打包技术 packh3 yi3,yi2,yh stdw yh:yl,*y++ //双字存取,提高执行效率 smpy2 yl,yl,yi1:yi0 sadd sum0,yi1,sum0 sadd sum0,yi0,sum0 smpy2 yh,yh,yi3:yi2 sadd sum0,yi3,sum0 sadd sum0,yi2,sum0 add i,-1,i b loop1 //把第一和第二个循环合成一个大循环,减少转移次数 产生的汇编代码并行流水性能大大增加,耗费的时钟周期数从1310000减少到15000,少于改编前的1/8。 6. 结束语 关于编解码器执行的时钟周期,在线性汇编改写前后,文件版本通过CCS的profiler剖析工具得知:每10帧(100MS)从159700000降至68500000,仅为原来的42%。硬件版本进行测试得:编解码的帧数提高到了88帧/s以上,鉴于编码、解码的时间比例为5:1,所以,本系统编码已经达到100帧/s,完全符合实时通信的要求。

试编写一个汇编语言程序,求出首地址为DATA的100个无符号字数组中的最小的书,并将它存放在BX寄存器

mov cx,50 ;循环次数 mov si,0 ;数据区指针,初始为第一个元素 mov ax,word ptr data ;把首字传送给axnext: cmp ax,word ptr data ;把数组的元素与ax比较 jb lop ;如果ax小于数组元素,转跳到lop mov ax,word ptr data ;否则把数组元素传送给axlop: inc si inc si ;指针指向下一个元素 loop next ;循环 mov bx,ax ;把最小值传送给bx

用汇编语言设计一个程序,求10个无符号数中的最大值并将最大值存入变量MAX中

***隐藏网址***25) 标号: MMS功能:求单字节十六进制有符号数据块的极值入口条件:数据块的首址在DPTR中,数据个数在R7中。出口信息:最大值在R6中, 地址在R2R3中;最小值在R7中,地址在R4R5中。影响资源:PSW、A、B、R1~R7 堆栈需求: 4字节MMS: MOV B,R7 ;保存数据个数MOVX A,@DPTR ;读取第一个数据MOV R6,A ;作为最大值的初始值MOV R7,A ;也作为最小值的初始值MOV A,DPL ;取第一个数据的地址MOV R3,A ;作为最大值存放地址的初始值MOV R5,A ;也作为最小值存放地址的初始值MOV A,DPHMOV R2,AMOV R4,AMOV A,B ;取数据个数DEC A ;减一,得到需要比较的次数JZ MMSE ;只有一个数据,不需要比较MOV R1,A ;保存比较次数PUSH DPL ;保护数据块的首址PUSH DPHMMS1: INC DPTR ;调整数据指针MOVX A,@DPTR ;读取一个数据MOV B,A ;保存SETB C ;与最大值比较SUBB A,R6JZ MMS4 ;相同,不更新最大值JNB OV,MMS2 ;差未溢出,符号位有效CPL ACC.7 ;差溢出,符号位取反MMS2: JB ACC.7,MMS4;差为负,不更新最大值MOV R6,B ;更新最大值MOV R2,DPH ;更新最大值存放地址MOV R3,DPLSJMP MMS7MMS4: MOV A,B ;与最小值比较CLR CSUBB A,R7JNB OV,MMS6 ;差未溢出,符号位有效CPL ACC.7 ;差溢出,符号位取反MMS6: JNB ACC.7,MMS7;差为正,不更新最小值MOV R7,B ;更新最小值MOV R4,DPH ;更新最小值存放地址MOV R5,DPLMMS7: DJNZ R1,MMS1 ;处理完全部数据POP DPH ;恢复数据首址POP DPLMMSE: RET

汇编语言程序题目!经典!困难!

code segmentmain proc farassume cs:code,ds:datastart:mov ax,datamov ds,axlea dx,msg1 ;out put msg1mov ah,09hint 21hlea dx,buf ;read stringmov ah,0ahint 21h……mov ah,4chint 21hcode ends end start这个程序太麻烦了,还要处理正负号以及小数点,实际操作中你可以单个数字输入,这样工作量小点,下面这个相关的程序作参考:按要求编程实现:输入若干整数保存在数据段中,求平均值;**********************************to_ave macro sum,num mov ax,sum div num endm;**********************************data segment maxlen db 4 actlen db ? numstr db 4 dup(?) sum dw 0 out_1 db ’Input a number:’,0dh,0ah,’$’ out_2 db ’Input again(end with #):’,0dh,0ah,’$’ out_3 db ’The average is : ’,’$’data ends;********************************** stack segment stack db 128 dup(?)stack ends;**********************************prognam segment;----------------------------------main proc far assume ss:stack,cs:prognam,ds:datastart: push ds sub ax,ax push ax mov ax,data mov ds,ax mov dx,offset out_1 mov ah,09h ;显示out_1字符串 int 21h lea dx,maxlen mov ah,0ah ;输入数字字符串 int 21h call near ptr proadd sub cl,cl ;计数器 inc clnext: mov dx,offset out_2 ;显示out_2字符串 mov ah,09h int 21h ;mov ah,0 ;int 16h ;cmp ax,1c0ah ;jz done lea dx,maxlen mov ah,0ah int 21h lea si,numstr cmp byte ptr ,’#’ jz done call near ptr proadd inc cl jmp nextdone: mov dx,offset out_3 mov ah,09h int 21h mov ax,n: to_ave ax,cl sub bx,bx ;bx计算循环的次数 inc bx call near ptr to_hex cmp ah,0 jz exit cmp bx,1 jnz contin push ax mov dl,’.’ mov ah,2 int 21h pop axcontin: add ah,ah mov al,ah add ah,ah add ah,ah add ah,al mov al,ah and ax,00ffh cmp bx,128 jz exit jmp n exit: retmain endp;----------------------------------crlf proc near push dx push ax mov dl,0dh mov ah,2 int 21h mov dl,0ah mov ah,2 int 21h pop ax pop dx retcrlf endp;----------------------------------to_hex proc near push ax push cx push dx mov ch,2 rotate: mov cl,4 rol al,cl push ax mov dh,al and dh,0fh add dh,30h cmp dh,3ah ;is it 》9 ? jl printit add dh,7hprintit: mov dl,dh mov ah,2 int 21h pop ax dec ch jnz rotate pop dx pop cx pop ax ret to_hex endp;----------------------------------proadd proc near push ax push bx push cx push dx push si mov cl, ;cl存储字符串长度 lea si,numstr ;si指向数字字符串 sub ch,ch sub bh,bh sub ax,axnest: add ax,ax ;ax的10倍 mov dx,ax add ax,ax add ax,ax add ax,dx mov bl, and bl,0fh add ax,bx inc si loop nest add ,ax pop si pop dx pop cx pop bx pop ax retproadd endp;--------------------------------prognam ends;******************************** end start 本人汇编能力有限,只能帮你这么多了

汇编指令 mov word ptr ds:[0],ss:[0] 哪里错了为什么提示 错误的数据类型的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于汇编指令 mov word ptr ds:[0],ss:[0] 哪里错了为什么提示 错误的数据类型、汇编指令 mov word ptr ds:[0],ss:[0] 哪里错了为什么提示 错误的数据类型的信息别忘了在本站进行查找哦。