汇编语言是一种最接近机器语言的编程语言。
有关汇编可参考另一篇文章:https://lobin.iteye.com/blog/2442219。
C是一种比较古老的强大的高级语言。在C语言中还可以内嵌汇编以实现更高级的功能。
内嵌汇编语法
在编写c程序时,在不同的平台下,选择不同的编译器,在内嵌汇编时的内嵌语法也不一样。如在VC下编写c程序时内嵌汇编语法:
_asm mov eax, edx;
完整代码:
#include<stdio.h> void main() { _asm mov eax, edx; }
如果是在gcc下编写c程序时内嵌汇编语法:
asm("mov %edx, %eax");
完整代码:
#include<stdio.h> void main() { asm("mov %edx, %eax"); }
上面是一个最简单的内嵌汇编的例子,内嵌语法上是不一样的,在这个例子中,虽然简单,但却是个很实用的例子,在调用汇编时,通常会将返回结果存在ax或eax中,调用结束后我们可以从ax或eax中得到调用结果。
VC下内嵌汇编语法
GCC下内嵌汇编语法
在后面给出的例子中,可能是在VC下内嵌汇编,也可能是在GCC下内嵌汇编的例子。这个是很容易区分的。
过程
汇编中的过程定义,下面是一个在MASM下的过程定义的例子
_test PROC NEAR push ebp mov ebp, esp ... ... pop ebp ret 0 _test ENDP
我们在编写C程序是,也可以编译查看对应的汇编程序代码。C程序中的函数在编译后对应汇编中的过程。如以下C程序
void test() { }
对应的汇编程序代码:
TITLE procedure_test0.c .386P include listing.inc if @Version gt 510 .model FLAT else _TEXT SEGMENT PARA USE32 PUBLIC 'CODE' _TEXT ENDS _DATA SEGMENT DWORD USE32 PUBLIC 'DATA' _DATA ENDS CONST SEGMENT DWORD USE32 PUBLIC 'CONST' CONST ENDS _BSS SEGMENT DWORD USE32 PUBLIC 'BSS' _BSS ENDS _TLS SEGMENT DWORD USE32 PUBLIC 'TLS' _TLS ENDS FLAT GROUP _DATA, CONST, _BSS ASSUME CS: FLAT, DS: FLAT, SS: FLAT endif PUBLIC _test _TEXT SEGMENT _test PROC NEAR ; File procedure_test0.c ; Line 3 push ebp mov ebp, esp ; Line 5 pop ebp ret 0 _test ENDP _TEXT ENDS END
其中有一个汇编过程(_test)
_test PROC NEAR push ebp mov ebp, esp pop ebp ret 0 _test ENDP
该过程对应C程序中的test函数。
上面的例子如果是在Cygwin GCC下,对应的汇编程序代码:
.file "procedure_test0.c" .text .globl _test .def _test; .scl 2; .type 32; .endef _test: pushl %ebp movl %esp, %ebp popl %ebp ret
如果是在linux环境下,GCC编译后对应的汇编程序代码和在Cygwin下有些不同:
.file "procedure_test0.c" .text .globl test .type test, @function test: pushl %ebp movl %esp, %ebp leave ret .size test, .-test .section .note.GNU-stack,"",@progbits .ident "GCC: (GNU) 3.4.6 20060404 (Red Hat 3.4.6-9)"
调用
参数传递
返回值
返回地址
堆栈平衡
堆栈平衡可参考另一篇文章:https://lobin.iteye.com/blog/2441310。
C调用汇编
汇编调用C
VC下C内嵌汇编
下面是个简单的c函数,求两个数的和:
int add(int a, int b) { return a + b; } void test_add() { int result = add(3, 4); } void main() { int result = add(3, 4); }
我们查看下对应的汇编代码,通过以下命令生成对应的汇编指令:
这里生成的汇编源代码文件是MASM的汇编源代码
汇编源代码(addtest.s):
TITLE addtest.c .386P include listing.inc if @Version gt 510 .model FLAT else _TEXT SEGMENT PARA USE32 PUBLIC 'CODE' _TEXT ENDS _DATA SEGMENT DWORD USE32 PUBLIC 'DATA' _DATA ENDS CONST SEGMENT DWORD USE32 PUBLIC 'CONST' CONST ENDS _BSS SEGMENT DWORD USE32 PUBLIC 'BSS' _BSS ENDS _TLS SEGMENT DWORD USE32 PUBLIC 'TLS' _TLS ENDS FLAT GROUP _DATA, CONST, _BSS ASSUME CS: FLAT, DS: FLAT, SS: FLAT endif PUBLIC _add _TEXT SEGMENT _a$ = 8 _b$ = 12 _add PROC NEAR ; File addtest.c ; Line 2 push ebp mov ebp, esp ; Line 3 mov eax, DWORD PTR _a$[ebp] add eax, DWORD PTR _b$[ebp] ; Line 4 pop ebp ret 0 _add ENDP _TEXT ENDS PUBLIC _test_add _TEXT SEGMENT _result$ = -4 _test_add PROC NEAR ; Line 7 push ebp mov ebp, esp push ecx ; Line 8 push 4 push 3 call _add add esp, 8 mov DWORD PTR _result$[ebp], eax ; Line 9 mov esp, ebp pop ebp ret 0 _test_add ENDP _TEXT ENDS PUBLIC _main _TEXT SEGMENT _result$ = -4 _main PROC NEAR ; Line 12 push ebp mov ebp, esp push ecx ; Line 13 push 4 push 3 call _add add esp, 8 mov DWORD PTR _result$[ebp], eax ; Line 14 mov esp, ebp pop ebp ret 0 _main ENDP _TEXT ENDS END
C嵌入汇编调用C函数
C嵌入汇编代码中可以通过call指令调用C函数。
#include<stdio.h> void test() { printf("fn test called\n"); } void main() { __asm call test; }
上面是通过call指令调用C函数,在汇编中我们还可以通过jmp指令来调用汇编过程,只需要在汇编过程实现和调用时维持好堆栈调用平衡。当然,也不一定非得维持好堆栈调用平衡,但最好维持平衡。所以这里也可以通过jmp指令来调用C函数。
在下面的例子中,通过jmp指令跳转到函数调用时,为了维持堆栈调用平衡,需要将调用返回后的指令地址压入栈,以便在函数调用返回时能够返回到调用时的下一条指令。
#include<stdio.h> void test() { printf("fn test called\n"); } void main() { __asm { push offset __RET; jmp test; __RET: ; blank } }
C内嵌汇编定义汇编Procedure,并在内嵌汇编中调用这个汇编Procedure。
汇编Procedure的定义,类似MASM中汇编Procedure的定义:
_TEXT SEGMENT _sum PROC NEAR push ebp mov ebp, esp mov eax, DWORD PTR 8[ebp] mov ecx, DWORD PTR 12[ebp] add eax, ecx pop ebp ret 0 _sum ENDP _TEXT ENDS
在下面的例子中模拟定义了一个叫__fn_test1和__fn_test2的汇编Procedure,并通过call调用。其中__fn_test1无参无返回值,__fn_test2接收2个参数并返回和。
#include<stdio.h> char __output_fn_test_fmt[] = "procedure __fn_test called.\n"; char __output_fmt[] = "a=%d, b=%d\n"; char __output_sum_fmt[] = "sum=%d\n"; int sum(int a1, int a2) { printf("sum called.\n"); return a1 + a2; } void test1() { // call procedure __fn_test __asm call __fn_test1; // after procedure __fn_test, jump to next instruction: // // __end: // printf("end.\n"); __asm jmp __end; // procedure __fn_test. // _TEXT SEGMENT // __fn_test PROC NEAR // push ebp // mov ebp, esp // ... // ... // pop ebp // ret 0 //_fx ENDP //_TEXT ENDS // // procedure __fn_test start. __asm __fn_test1: push ebp; __asm mov ebp, esp; __asm push offset __output_fn_test_fmt; __asm call printf; __asm pop ebx; // call fn(printf), with args __output_fmt, 111 and 222 __asm push 111; __asm push 222; __asm push offset __output_fmt; __asm call printf; __asm pop ebx; __asm pop ebx; __asm pop ebx; // call fn(sum), with args 111 and 222 __asm push 111; __asm push 222; __asm call sum; __asm pop ebx; __asm pop ebx; // call fn(printf) with args __output_sum_fmt and result of sum __asm push eax; __asm push offset __output_sum_fmt; __asm call printf; __asm pop ebx; __asm pop ebx; __asm pop ebp; __asm ret 0; // __fn_test end. __end: printf("end.\n"); } int test2(int a, int b) { int result = 0; // call procedure __fn_test __asm push a; __asm push b; __asm call __fn_test2; __asm pop ebx; __asm pop ebx; __asm mov result, eax // after procedure __fn_test, jump to next instruction: // // __end: // printf("end.\n"); __asm jmp __end; // procedure __fn_test. // _TEXT SEGMENT // __fn_test PROC NEAR // push ebp // mov ebp, esp // ... // ... // pop ebp // ret 0 //_fx ENDP //_TEXT ENDS // // procedure __fn_test start. __asm __fn_test2: push ebp; __asm mov ebp, esp; __asm push offset __output_fn_test_fmt; __asm call printf; __asm pop ebx; // call fn(printf), with args __output_fmt, 111 and 222 __asm push DWORD PTR 8[ebp]; __asm push DWORD PTR 12[ebp]; __asm push offset __output_fmt; __asm call printf; __asm pop ebx; __asm pop ebx; __asm pop ebx; // call fn(sum), with args 111 and 222 __asm push DWORD PTR 8[ebp]; __asm push DWORD PTR 12[ebp]; __asm call sum; __asm pop ebx; __asm pop ebx; __asm push eax; // call fn(printf) with args __output_sum_fmt and result of sum __asm push eax; __asm push offset __output_sum_fmt; __asm call printf; __asm pop ebx; __asm pop ebx; __asm pop eax; __asm pop ebp; __asm ret 0; // __fn_test end. __end: printf("end.\n"); return result; } void main() { printf("test 1\n"); test1(); printf("test 2\n"); printf("result: %d\n", test2(11, 22)); }
在下面的例子中模拟定义了一个叫__fn_test1的汇编Procedure,并通过call调用。__fn_test1
无参无返回值,__fn_test1内部关键部分采用_emit。
#include<stdio.h> char __output_fmt[] = "a=%d, b=%d\n"; void main() { __asm { call __fn_test1 ; call offset __fn_test1 push eax; push eax; push offset __output_fmt; call printf; pop ebx; pop ebx; pop ebx; jmp offset __end ; jmp __end } __asm { __fn_test1: _emit 0x55 ; push ebp _emit 0x8B ; v _emit 0xEC ; mov ebp, esp // call fn(printf), with args __output_fmt, 111 and 222 _emit 0x6A ; v _emit 0x6F ; push 111; _emit 0x68 ; | _emit 0xDE ; | _emit 0x00 ; | _emit 0x00 ; v _emit 0x00 ; push 222; push offset __output_fmt; //push __output_fmt; call printf; // call offset printf; _emit 0x5B ; pop ebx; _emit 0x5B ; pop ebx; _emit 0x5B ; pop ebx; _emit 0xB8 _emit 0x64 _emit 0x00 _emit 0x00 _emit 0x00 ; mov eax, 64h _emit 0x5D ; pop ebp //_emit 0xC2 ; | //_emit 0x00 ; v //_emit 0x00 ; ret 0 _emit 0xC3 ; ret } __end: printf("end."); }
在下面的例子中通过一个数组模拟定义了一个汇编Procedure,并通过call调用。该模拟的汇编Procedure无参无返回值,汇编Procedure通过机器码实现。
#include<stdio.h> char __output_fmt[] = "a=%d, b=%d\n"; void main() { //char ___fn[] = {0x55, 0x8B, 0xEC, 0x5D, 0xC2, 0x00, 0x00}; // push ebp; mov ebp, esp; pop ebp; ret 0 //char ___fn[] = {0x55, 0x8B, 0xEC, 0x5D, 0xC3}; // push ebp; mov ebp, esp; pop ebp; ret char ___fn[] = {0x55, 0x8B, 0xEC, 0xB8, 0x64, 0x00, 0x00, 0x00, 0x5D, 0xC3}; // push ebp; mov ebp, esp; mov eax, 64h; pop ebp; ret char *__ptr_fn = ___fn; unsigned int __intptr_fn = (unsigned int) __ptr_fn; __intptr_fn = (unsigned int) ___fn; __asm { push eax; push eax; push offset __output_fmt; call printf; pop ebx; pop ebx; pop ebx; call __intptr_fn push eax; push eax; push offset __output_fmt; call printf; pop ebx; pop ebx; pop ebx; jmp offset __end ; jmp __end } __end: printf("end."); }
C调用汇编
callasmtest.c
#include<stdio.h> int sum(int a, int b); int main(int argc, char *argv[]) { int num = sum(11, 22); printf("sum: %d\n", num); _asm push 111; _asm push 222; _asm call sum; _asm pop ebx; _asm pop ebx; _asm mov num, eax; printf("sum: %d\n", num); return 0; }
sum.asm
TITLE sum.asm .386P _TEXT SEGMENT _sum PROC NEAR push ebp mov ebp, esp mov eax, DWORD PTR 8[ebp] mov ecx, DWORD PTR 12[ebp] add eax, ecx pop ebp ret 0 _sum ENDP _TEXT ENDS END
>ml /c /coff sum.asm >cl /c callasmtest.c callasmtest.obj >cl /Fecallasmtest.exe sum.obj callasmtest.obj >.\callasmtest.exe sum: 33
GCC下内嵌汇编
这里有一篇对8086介绍的比较透彻的文章:https://www.cnblogs.com/zhaoyl/archive/2012/05/15/2501972.html
关于C/C++可参考另一篇文章:https://lobin.iteye.com/blog/620212
BOSH initiate a session(A XMPP extension protocol transport over HTTP)
相关推荐
内嵌汇编编程是C语言与底层硬件交互的一种重要方式,允许程序员直接在C程序中嵌入汇编语言代码,利用汇编语言直接操作硬件的灵活性,同时又保留了C语言的高级特性。混合编程具有以下几个知识点: 1. 内嵌汇编的优势...
这个例子中,`asm volatile`关键字启动内嵌汇编,`%0`和`%1`分别代表第一个和第二个操作数,它们对应于C/C++变量`value`和`address`。 使用内嵌汇编时需要注意几点: - **移植性**:内嵌汇编会降低代码的可移植性,...
由于GCC(GNU Compiler Collection)编译器的广泛应用,其内嵌汇编语言成为一种在C语言源代码中插入汇编指令的便捷方法。这种技术允许开发者混合使用高级语言的便利性和汇编语言的性能优化。 内嵌汇编语言主要应用...
在x64系统中实现内嵌汇编,即在高级语言(如C++或C)的源代码中直接插入汇编代码,可以用于优化特定性能敏感的代码段或执行一些硬件直接交互的任务。 内嵌汇编的基本原理是将汇编语言指令与高级语言代码混合编写,...
C语言内嵌ARM汇编是一种将底层硬件操作与高级编程语言相结合的技术,它允许程序员在C代码中直接插入ARM架构的汇编指令,以实现特定的性能优化或硬件交互。ARM汇编语言是针对ARM处理器设计的一种低级编程语言,具有...
GCC内嵌汇编是一种特殊的C语言特性,允许程序员在C/C++代码中直接嵌入汇编代码。这种方式可以用于优化性能关键的部分,或者实现C语言本身无法表达的操作。 ##### 2.1 简介 GCC内嵌汇编提供了灵活的方式来编写特定...
GCC内嵌汇编是一种特殊的C/C++语法,它允许程序员直接在C/C++程序中编写汇编代码,以实现性能优化或访问硬件等目的。了解GCC内嵌汇编的基本概念和使用方法对于编写高效、底层的代码至关重要。 ##### 2.1 简介 GCC...
内嵌汇编是指在C/C++源代码中直接插入汇编指令的能力。这对于优化特定功能或直接控制硬件访问非常重要。下面我们将讨论几种常见的内嵌汇编方法及其应用场景。 #### 三、内嵌汇编示例分析 ##### 3.1 示例1: 使用`__...
内嵌汇编是GCC(GNU Compiler Collection)提供的一个强大特性,允许开发人员在C/C++代码中直接嵌入汇编指令,以此来实现某些特定功能或者优化性能。内嵌汇编通过`__asm__`和`__volatile__`关键字实现,其基本格式...
GCC(GNU Compiler Collection)作为一款广泛使用的开源编译器套件,支持多种编程语言,包括C、C++等,并且具备内嵌汇编的功能。这使得开发人员能够在C语言程序中直接编写汇编代码,以实现对底层硬件更精细的控制...
GCC 内嵌汇编是指在高级语言(如 C、C++)中嵌入汇编语言的代码,以提高程序的执行效率。在本文中,我们将对 AT&T 汇编语言与 GCC 内嵌汇编进行简介,介绍它们的语法和使用方法。 1. AT&T 汇编语言语法 AT&T 汇编...
在内嵌汇编中可以直接引用 C 语言中的变量,例如进行加法运算: ```c int a = 100; int b = 200; asm__volatile__( "add r1, %[aa], %[bb]\n\t" : : [aa] "r" (a), [bb] "r" (b) ); ``` #### 3.2 变量赋值 还...
输出部分指定GCC内嵌汇编的输出操作数,它位于冒号后面的第一组圆括号内。例如,`"=r"(dest)`意味着dest变量是输出操作数,将被赋值。 #### 输入部分 输入部分位于输出部分之后的一组圆括号内,它指定GCC内嵌汇编的...
ARM汇编语言与嵌入式C语言混合编程内嵌汇编.pdf
GCC提供了强大的扩展能力,其中之一便是支持在C语言中嵌入汇编代码的能力,即所谓的“内嵌汇编”。这项特性允许开发者直接在C代码中编写汇编指令,从而实现更底层的控制或者优化性能。 #### 二、gcc内嵌汇编的基本...
c语言内嵌汇编
### GCC内嵌汇编知识点详解 #### 一、GCC内嵌汇编简介 GCC(GNU Compiler Collection)作为一套广泛使用的开源编译器集合,在支持多种编程语言的同时也提供了内嵌汇编的功能。这一功能允许开发者在C/C++代码中直接...
其中,GCC内嵌汇编是GCC提供的一种特殊语法,允许开发者在C/C++代码中直接插入汇编指令,这对于实现某些底层优化或硬件访问来说非常有用。 #### 二、内嵌汇编语法结构 GCC内嵌汇编语法主要包括以下四个部分: 1. *...