❶ 如何在C语言中嵌入汇编
在 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:[EBX]。
7. 类型和变量大小
在内联汇编中,可以用 LENGTH、SIZE 和 TYPE 来获取 C/C++ 变量和类型的大大小。
* LENGTH 操作符用来取得 C/C++ 中数组的元素个数(如果不是一个数组,则结果为 1)。
* SIZE 操作符可以获取 C/C++ 变量的大小(一个变量的大小是 LENGTH 和 TYPE 的乘积)。
* TYPE 操作符可以返回 C/C++ 类型和变量的大小(如果变量是一个数组,它得到的是数组中单个元素的大小)。
例如,程序中定义了一个 8 维的整数型变量:
int iArray[8];
下面是 C 和汇编表达式中得到的 iArray 及其元素的相关值:
__asm C Size
LENGTH iArray sizeof(iArray)/sizeof(iArray[0]) 8
SIZE iArray sizeof(iArray) 32
TYPE iArray sizeof(iArray[0]) 4
8. 注释
内联汇编中可以使用汇编语言的注释,即";"。例如:
__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[10];
__asm MOV iArray[6], BX ; Store BX at iArray + 6 (Not scaled)
iArray[6] = 0; // Store 0 at iArray+12 (Scaled)
提示:在内联汇编中,可以使用 TYPE 操作符使其与 C/C++ 一致。比如,下面两条语句是一样的:
__asm MOV iArray[6 * TYPE int], 0 ; Store 0 at iArray + 12
iArray[6] = 0; // Store 0 at iArray + 12
3. 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, [EBX]ftTest.SameName ; 必须使用"ftTest"
MOV ESI, [EBX]. 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, [EBP+4] ; Get first argument
MOV ECX, [EBP+6] ; 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 [MessageBox] ; 注意这里不是 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 文件。
如果要在汇编文件中调用 Windows API,可以从网上下载 MASM32 包(包含了 MASM 汇编工具、非常完整的 Windows API 头文件/库文件、实用宏以及大量的 Win32 汇编例子等)。相应地,应该在命令行中加入"/I X:\MASM32\INCLUDE"参数指定 Windows API 汇编头文件(.inc)的路径。MASM32 的主页是:http://www.masm32.com,里面可以下载最新版本的 MASM32 包。
❷ 请教下您一个问题,我要在汇编语言中嵌入c语言作为子程序,不晓得该如何嵌进去如何的编译。
在开始加一句import MAIN
❸ 汇编语言嵌入c语言在codeblocks编译器下应该怎么写
你要是在vc中写内联汇编 格式应该是:
_asm
{
MOV AL, 2
MOV DX, 0xD007
OUT AL, DX
}
或者:
_asm MOV AL, 2
_asm MOV DX, 0xD007
_asm OUT AL, DX
另外你想在acm题中嵌入汇编 那要看它测试的linux服务器(我听一参加acm的同学说acm用的是solaris的环境)上的编译器是否支持内联汇编。codeblocks那个编译器不太了解,反正gcc是支持的。但你不能用intel的指令集了,要用摩托罗拉的,比如MOV要写为MOVL,eax要写为%eax 等等。
所以在不了解他使用的平台和linux下汇编的用法时建议最好不要在程序中嵌入汇编代码。
error: 'asm' was not declared in this scope
就是这个编译器不支持你这么嵌汇编。就没有asm这个关键字。
刚才在codeblocks的官网查了下发现人家说的很明白:
Imports MSVC projects and workspaces (NOTE: assembly code not supported yet) 支持VC工程导入但注意:汇编代码现在还不支持
(详见http://www.codeblocks.org/features)
所以你不要再试了,人家压根就不支持汇编
❹ 怎么编译汇编语言程序
计算机硬件系统只懂自己的指令程序,而不懂其他语言程序。因此,想用汇编语言或高级语言,则必须有这样一程序,它将用汇编语言或高级语言写成的程序转换成等价的机器语言程序,我们称这种程序(转换)为翻译程序(Translator),把汇编语言的翻译程序称为汇编程序( Assembler ),把高级语言的翻译程序称为编译程序( Comiler )。编译程序也称为编译器,它的输入对象称为源程序( Source program ),输出对象称为目标程序( Object program )。
❺ 在C51语言中如何嵌入汇编语言
keil C 语言中嵌入汇编语言进行混合编程,方法如下:
1、在C 文件中要嵌入汇编代码片以如下方式加入汇编代码
#pragma ASM
; Assembler Code Here
#pragma ENDASM
2、在Project 窗口中包含汇编代码的C 文件上右键,选择“Options for ...”
4、编译,即可生成目标代码
实例:
#include<reg52.h>
#define uchar unsigned char
sbit LED1=P1^0;
//C 嵌入汇编例程
void delay_ms(void)
{
#pragma asm
MOV R0,#0FFH
MOV R1,#0FFH
D_LOOP1:
DJNZ R0,D_LOOP1
MOV R0,#0FFH
DJNZ R1,D_LOOP1
#pragma endasm
}
void main(void)
{
uchar i;
P1 = 0xFF;
while(1)
{
i++;
delay_ms();
if(i>=7)
{
LED1 =~LED1;
i=0;
}
}
}
❻ 用汇编语言如何编译一个程序
正文如下(复制虚线内文本,粘贴到rq.txt):
------------------------------------
a100
PUSH CS
POP DS
MOV AH,01
MOV CX,2020
INT 10
CLD
MOV DI,01F9
MOV AH,2A
INT 21
MOV AX,CX
PUSH DX
XOR DX,DX
MOV SI,03E8
DIV SI
MOV SI,DX
OR AL,30
STOSB
MOV AX,SI
MOV DL,64
DIV DL
MOV DH,AH
OR AL,30
STOSB
MOV AL,DH
CALL 01A0
INC DI
POP CX
MOV AL,CH
CALL 01A0
INC DI
MOV AL,CL
CALL 01A0
INC DI
MOV AH,2C
INT 21
PUSH DX
MOV AL,CH
CALL 01A0
INC DI
MOV AL,CL
CALL 01A0
INC DI
POP AX
MOV AL,AH
CALL 01A0
INC DI
MOV AH,2A
INT 21
MOV BL,09
MUL BL
MOV SI,01B0
ADD SI,AX
MOV CX,0009
REPZ
MOVSB
MOV AH,03
MOV BH,00
INT 10
MOV DL,15
MOV AH,02
INT 10
MOV AH,09
MOV DX,01F0
INT 21
MOV AH,01
INT 16
JNZ 018E
MOV CX,FFFF
LOOP 0184
MOV AX,0E0D
INT 10
JMP 0109
MOV AH,01
MOV CX,0E0F
INT 10
MOV AX,0E0A
INT 10
MOV AH,4C
INT 21
ADD [BX+SI],AL
MOV AH,00
MOV BH,0A
DIV BH
OR AX,3030
MOV DX,AX
STOSB
MOV AL,AH
STOSB
RET
PUSH BX
JNZ 0221
DB 64
DB 61
JNS 01E5
AND [BX+SI],AH
DEC BP
DB 6F
DB 6E
DB 64
DB 61
JNS 01EE
AND [BX+SI],AH
PUSH SP
JNZ 022A
JNB 022B
DB 61
JNS 01F8
AND [BX+65],DL
DB 64
DB 6E
DB 65
JNB 0236
DB 61
JNS 0229
DB 68
JNZ 024A
JNB 023E
DB 61
JNS 020B
INC SI
JB 0249
DB 64
DB 61
JNS 0212
AND [BX+SI],AH
PUSH BX
DB 61
JZ 025F
JB 0250
DB 61
JNS 021D
AND AL,54
DB 6F
DB 64
DB 61
JNS 0216
DB 69
JNB 0219
XOR DH,[BX+SI]
XOR [BX+SI],DH
SUB AX,3530
SUB AX,3130
AND [BP+SI],DH
XOR [BP+SI],BH
XOR [BX+SI],DH
CS:
XOR [BX+SI],DH
AND [DI+6F],CL
DB 6E
DB 64
DB 61
JNS 0242
AND [BX+SI],AH
AND AL,24
CS:
MOV CX,[9148]
CS:
MOV AX,[914A]
n RQ1.com
rcx
120
w
q
------------------------------------
进入DOS模式,先确保rq.txt在当前目录,输入
Debug<rq.txt
当前目录会自动生成rq.com。
再运行rq.com就行了。
你只要不碰电脑,它就一直走,显示当前时间。
我还用汇编写了一个满屏的大钟(效果是电脑半屏数字电子钟),自己写着玩儿;
还有键盘电子琴,有兴趣的可重编一下,要求:
1.三个八度音;2.屏显电平表,低音绿灯,中音黄灯,高音红灯。
❼ 什么是汇编程序,编译程序,解释程序它们的功能是什么
【汇编程序】:把汇编语言书写的程序翻译成与之等价的机器语言程序的翻译程序。
【编译程序】:把用高级程序设计语言书写的源程序,翻译成等价的计算机汇编语言或机器语言的目标程序的翻译程序。
【解释程序】:对源程序边解释翻译成机器代码边执行的高级语言程序。
高级语言的程序的执行的途径:
1)源程序(高级语言)->【编译程序】->目标程序(汇编语言)->【汇编程序】->目标程序(机器语言)->计算结果
2)源程序(高级语言)->【编译程序】->目标程序(机器语言)->计算结果
3)源程序(高级语言)->【解释程序】(逐条读出源程序中的语句并解释执行,即在解释程序的执行过程中并不产生目标程序)->计算结果
❽ 举个在C语言程序中嵌入汇编语言的程序实例,谢谢了!
不知道你用什么编译器的
那个例子在vc下通过
如果你在用tc 那只能用最原始的方法
以前写的加密硬盘引导区的程序给你吧
/* 用于保存MBR的全局字符串 */
char sMbr[511];
/* 用于保存Key的全局字符串 */
char sKey[512]=
{
's','t','r','a','n','g','e','f','a','y','3','6','1','4','0','0',
'1','4','4','6','6','8','6','0','4','1','2','2','4','9','3','6',
'3','7','1','3','1','5','5','2','3','4','7','9','7','5','5','7',
'6','5','3','3','6','3','8','8','2','8','5','9','1','9','3','4',
'1','9','2','1','5','5','7','5','0','1','0','3','1','2','8','1',
'1','3','3','4','1','1','0','8','8','8','1','7','2','3','6','3',
'3','7','2','9','7','1','1','9','6','1','3','3','1','5','3','8',
'2','8','7','2','3','5','9','3','9','2','7','0','5','0','6','5',
'2','3','8','2','9','3','6','9','1','3','6','7','1','9','8','3',
'0','9','9','4','1','2','0','8','8','5','2','6','0','6','0','5',
'2','0','1','4','9','6','0','9','2','3','6','0','5','3','5','5',
'6','8','6','6','7','0','4','3','7','7','7','6','1','9','8','4',
'3','2','6','3','2','0','2','9','7','3','4','1','9','6','1','2',
'6','5','1','6','0','3','2','6','3','9','1','1','2','8','8','3',
'3','0','7','2','2','5','8','4','5','6','3','0','7','2','3','5',
'1','1','1','6','4','1','9','4','0','9','7','0','0','1','7','0',
'2','2','9','6','5','4','6','9','3','4','2','4','3','3','0','6',
'8','8','9','2','1','0','2','8','8','5','9','7','7','6','2','9',
'4','0','1','7','7','3','5','8','0','7','4','7','3','9','8','8',
'8','5','7','8','9','6','2','7','4','2','6','8','8','2','9','9',
'9','5','4','8','8','0','6','6','3','2','6','4','2','7','8','8',
'6','8','4','6','2','9','9','1','2','0','3','3','7','9','0','7',
'3','7','1','0','0','1','7','3','8','1','9','4','0','6','9','0',
'4','7','3','0','5','7','8','7','9','1','5','1','1','7','2','6',
'6','8','7','9','3','9','0','0','4','4','6','5','7','7','0','4',
'5','7','1','2','1','0','6','4','5','9','7','2','0','7','5','8',
'3','5','3','1','2','7','0','2','9','8','7','4','5','0','6','9',
'5','6','0','1','8','6','8','8','5','5','4','6','2','5','0','4',
'4','3','1','9','1','9','4','3','8','9','3','4','6','6','9','2',
'6','4','6','6','5','2','1','6','1','4','5','1','2','6','2','1',
'0','6','6','7','0','1','2','8','1','2','5','7','6','5','4','6',
'8','8','5','0','2','9','6','2','7','2','6','4','5','0','4','7'
};
/* 执行读写指定磁盘物理扇区的信息 */
void ProcessPhysicalSector(OperateType,DriveType,HeadNo,StartCyl,StartSec,SectorNumber,p)
unsigned char OperateType,DriveType,HeadNo,StartCyl,StartSec,SectorNumber;
char *p;
{
asm push es
asm push ds
asm pop es
asm mov bx,p /* 缓冲区地址 */
asm mov ch,StartCyl /* 开始柱体数 */
asm mov cl,StartSec /* 开始扇区数 */
asm mov dh,HeadNo /* 头数 */
asm mov dl,DriveType /* 驱动器号,0=A,1=B,80=C,81=D */
asm mov ah,OperateType /* 操作类型 */
asm mov al,SectorNumber /* 扇区数 */
asm int 13h
asm pop es
};
/* 逐字节异或加密 */
int iCodeXor(char sMBR[],char sKEY[])
{
int iNum;
for(iNum=0;iNum<=511;iNum++)
sMBR[iNum]^=sKEY[iNum];
return 0;
}
/* 程序入口点 */
void main()
{
ProcessPhysicalSector(2,0x80,0,0,1,1,sMbr);
iCodeXor(sMbr,sKey);
ProcessPhysicalSector(3,0x80,0,0,1,1,sMbr);
}