`
lobin
  • 浏览: 425459 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

C 第2500章: 内嵌汇编

 
阅读更多

汇编语言是一种最接近机器语言的编程语言。

 

有关汇编可参考另一篇文章: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的汇编源代码

写道
>cl /c /Faaddtest.s addtest.c /Foaddtest.obj

 

汇编源代码(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)

  • 大小: 55.9 KB
分享到:
评论

相关推荐

    C语言内嵌汇编编程

    内嵌汇编编程是C语言与底层硬件交互的一种重要方式,允许程序员直接在C程序中嵌入汇编语言代码,利用汇编语言直接操作硬件的灵活性,同时又保留了C语言的高级特性。混合编程具有以下几个知识点: 1. 内嵌汇编的优势...

    ARM_GCC内嵌汇编

    这个例子中,`asm volatile`关键字启动内嵌汇编,`%0`和`%1`分别代表第一个和第二个操作数,它们对应于C/C++变量`value`和`address`。 使用内嵌汇编时需要注意几点: - **移植性**:内嵌汇编会降低代码的可移植性,...

    gcc中的内嵌汇编语言

    由于GCC(GNU Compiler Collection)编译器的广泛应用,其内嵌汇编语言成为一种在C语言源代码中插入汇编指令的便捷方法。这种技术允许开发者混合使用高级语言的便利性和汇编语言的性能优化。 内嵌汇编语言主要应用...

    x64下实现内嵌汇编

    在x64系统中实现内嵌汇编,即在高级语言(如C++或C)的源代码中直接插入汇编代码,可以用于优化特定性能敏感的代码段或执行一些硬件直接交互的任务。 内嵌汇编的基本原理是将汇编语言指令与高级语言代码混合编写,...

    C语言内嵌arm汇编

    C语言内嵌ARM汇编是一种将底层硬件操作与高级编程语言相结合的技术,它允许程序员在C代码中直接插入ARM架构的汇编指令,以实现特定的性能优化或硬件交互。ARM汇编语言是针对ARM处理器设计的一种低级编程语言,具有...

    AT&T汇编语言与GCC内嵌汇编简介

    GCC内嵌汇编是一种特殊的C语言特性,允许程序员在C/C++代码中直接嵌入汇编代码。这种方式可以用于优化性能关键的部分,或者实现C语言本身无法表达的操作。 ##### 2.1 简介 GCC内嵌汇编提供了灵活的方式来编写特定...

    AT&T汇编语言与GCC内嵌汇编简介.pdf

    GCC内嵌汇编是一种特殊的C/C++语法,它允许程序员直接在C/C++程序中编写汇编代码,以实现性能优化或访问硬件等目的。了解GCC内嵌汇编的基本概念和使用方法对于编写高效、底层的代码至关重要。 ##### 2.1 简介 GCC...

    在C 中内嵌汇编.docx

    内嵌汇编是指在C/C++源代码中直接插入汇编指令的能力。这对于优化特定功能或直接控制硬件访问非常重要。下面我们将讨论几种常见的内嵌汇编方法及其应用场景。 #### 三、内嵌汇编示例分析 ##### 3.1 示例1: 使用`__...

    gcc内嵌汇编

    内嵌汇编是GCC(GNU Compiler Collection)提供的一个强大特性,允许开发人员在C/C++代码中直接嵌入汇编指令,以此来实现某些特定功能或者优化性能。内嵌汇编通过`__asm__`和`__volatile__`关键字实现,其基本格式...

    GCC内嵌汇编语法

    GCC(GNU Compiler Collection)作为一款广泛使用的开源编译器套件,支持多种编程语言,包括C、C++等,并且具备内嵌汇编的功能。这使得开发人员能够在C语言程序中直接编写汇编代码,以实现对底层硬件更精细的控制...

    AT&T汇编语言与GCC内嵌汇编简介[定义].pdf

    GCC 内嵌汇编是指在高级语言(如 C、C++)中嵌入汇编语言的代码,以提高程序的执行效率。在本文中,我们将对 AT&T 汇编语言与 GCC 内嵌汇编进行简介,介绍它们的语法和使用方法。 1. AT&T 汇编语言语法 AT&T 汇编...

    内嵌汇编.txt

    在内嵌汇编中可以直接引用 C 语言中的变量,例如进行加法运算: ```c int a = 100; int b = 200; asm__volatile__( "add r1, %[aa], %[bb]\n\t" : : [aa] "r" (a), [bb] "r" (b) ); ``` #### 3.2 变量赋值 还...

    AT&T汇编语言与gcc内嵌汇编简介

    输出部分指定GCC内嵌汇编的输出操作数,它位于冒号后面的第一组圆括号内。例如,`"=r"(dest)`意味着dest变量是输出操作数,将被赋值。 #### 输入部分 输入部分位于输出部分之后的一组圆括号内,它指定GCC内嵌汇编的...

    ARM汇编语言与嵌入式C语言混合编程内嵌汇编.pdf

    ARM汇编语言与嵌入式C语言混合编程内嵌汇编.pdf

    gcc内嵌汇编 中文使用说明

    GCC提供了强大的扩展能力,其中之一便是支持在C语言中嵌入汇编代码的能力,即所谓的“内嵌汇编”。这项特性允许开发者直接在C代码中编写汇编指令,从而实现更底层的控制或者优化性能。 #### 二、gcc内嵌汇编的基本...

    c语言内嵌汇编

    c语言内嵌汇编

    GCC内嵌汇编的一些资料

    ### GCC内嵌汇编知识点详解 #### 一、GCC内嵌汇编简介 GCC(GNU Compiler Collection)作为一套广泛使用的开源编译器集合,在支持多种编程语言的同时也提供了内嵌汇编的功能。这一功能允许开发者在C/C++代码中直接...

    gcc内嵌汇编语法

    其中,GCC内嵌汇编是GCC提供的一种特殊语法,允许开发者在C/C++代码中直接插入汇编指令,这对于实现某些底层优化或硬件访问来说非常有用。 #### 二、内嵌汇编语法结构 GCC内嵌汇编语法主要包括以下四个部分: 1. *...

Global site tag (gtag.js) - Google Analytics