| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 5435 人关注过本帖
标题:菜鸟请教 ,怎么用汇编调用C函数,怎么用C调用汇编写的函数,他们的参数是怎 ...
只看楼主 加入收藏
zjsxwc
Rank: 7Rank: 7Rank: 7
等 级:黑侠
威 望:1
帖 子:252
专家分:601
注 册:2011-1-20
结帖率:93.75%
收藏
已结贴  问题点数:0 回复次数:7 
菜鸟请教 ,怎么用汇编调用C函数,怎么用C调用汇编写的函数,他们的参数是怎么传递的?
RT啊
搜索更多相关主题的帖子: 信息 
2011-07-15 20:31
zklhp
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:china
等 级:贵宾
威 望:254
帖 子:11485
专家分:33241
注 册:2007-7-10
收藏
得分:0 
考虑到C语言与汇编语言的接近程度,在此只介绍这二种程序设计语言之间的接口问题。

了解的内容:C语言源程序生成汇编语言的源程序的方法,从所生成的汇编语言源程序中,看出C语言语句用汇编语言实现的技巧,从而对C语言语句的语义有一个更进一步的理解。

掌握的内容:C语言函数参数的传递方法,在汇编语言中读取C语言函数参数的方法。

建议学习时间:2小时。
第12章 汇编语言和C语言
C/C++语言是一个被广泛使用的程序设计语言,它不仅具有良好的高级语言特征,而且还具有一些低级语言的特点,如:寄存器变量、位操作等。所以,C语言的程序与汇编语言程序之间能很平滑地衔接。另外,目前主要的C语言程序开发环境,如:Turbo C/C++、Borland C/C++等,也都提供了很好的混合编程手段。

本章主要介绍汇编语言和C语言的混合编程和调用方法。虽然其它高级语言,如:Pascal、Basic等,也可与汇编语言混合使用,但出于其应用范围的考虑,不再对它们进行介绍,感兴趣的读者可参阅有关技术资料。

12.1 汇编指令的嵌入
为了提高C语言程序内某特殊功能段的处理效率,我们可以在其源程序中嵌入一段汇编语言程序段。这样做,虽然能达到提高了程序处理效率的目的,但它无疑以丧失源程序的可移植性为代价。所以,当想用C语言和汇编语言混合编程时,程序员需要权衡采用这种方法的利与弊。

在C语言中,嵌入汇编语言的语法如下(*):

asm <opcode> <operands> <; or newline>

注意:这里的分号';'不是汇编语言中起注释作用的分号,而是作为语句的分隔符。

若C语言源程序中嵌入一条汇编语句,则可按下列方式来做:

asm mov ax, data

若要嵌入一组汇编语句,则需要用括号'{'和'}'把它们括起来。

asm {
   mov ax, data1
   xchg ax, data2
   mov data1, ax     //实现整型变量data1和data2之值的交换
}

例12.1 在C语言源程序中嵌入汇编语言语句实现赋值语句A=A+B+C,其中:A、B、C都是整型变量。

解: ……

asm {push ax      //实现整型变量A=A+B+C
  mov ax, A
  add ax, B
  add ax, C
  mov A, ax
  pop ax
}
12.2 C语言程序的汇编输出
在Turbo C++或Borland C++编程环境下,我们可TCC或BCC行命令把一个C语言的源程序转换成汇编语言的源程序。通过阅读汇编语言程序可以很准确地知道C语言语句的功能是如何实现的,这样,可为将来学习《编译原理》课程中的"寄存器调度"和"代码生成"等相关知识打下良好的基础。

C语言源程序转换的命令格式如下:

TCC -S t1.cpp 或 BCC -S t1.cpp   ;假设其文件名为t1.cpp

若命令TCC/BCC不带参数的话,则将显示其使用方法。

下面是C语言程序及其相对应的汇编语言程序,希望读者能逐行对照理解它们语句之间的转换关系,这将能进一步理解高级语言的语句功能。

1、C语言程序清单

#include <stdio.h>
int sum(int a, int b, int c)
 {
  return (a+b+c);
 }
void main()
{int a, b, c;
 a = b = 12;
 c = 32;
 printf("%d", sum(a,b,c));
}

2、生成的汇编语言程序清单

 ……                      ;一系列辅助说明信息
 _TEXT segment byte public 'CODE'      ;代码段的开始
 ;int sum(int a, int b, int c)           ;C语言语句  
       assume  cs : _TEXT
@sum$qiii proc  near            ;过程说明,对应于C语言sum过程
      push bp             ;为读取堆栈中的参数作准备,可参见第7.3.3节内容
      mov bp, sp
 ;{
  ;return(a+b+c);  
       mov ax, word ptr [bp+4]
      add ax, word ptr [bp+6]
      add ax, word ptr [bp+8]
      jmp short @1@58
@1@58:
 ;}  
       pop bp              ;sum子程序结束的代码
      ret
@sum$qiii endp
 ;void main()       assume  cs : _TEXT
_main   proc  near             ;过程说明,对应于C语言中的主函数main()
      push bp
      mov bp, sp
      sub sp, 6
 ;{int a, b, c;                  ;局部变量是用堆栈来存储的,请见第7.5.10节
 ; a = b = 12;                  ;给局部变量赋值
       mov ax, 12            ;用给堆栈单元赋值来实现对局部变量的赋值
      mov word ptr [bp-4], ax
      mov word ptr [bp-2], ax
 ; c = 32;       mov word ptr [bp-6], 32
 ; printf("%d", sum(a,b,c));            ;调用系统标准函数       push word ptr [bp-6]
      push word ptr [bp-4]
      push word ptr [bp-2]
      call near ptr @sum$qiii      ;用汇编语言形式调用自定义函数sum
      add sp, 6
      push ax
      mov ax, offset DGROUP : s@
      push ax
      call near ptr _printf        ;用汇编语言调用标准函数printf
      pop cx
      pop cx
 ; }       mov  sp, bp            ;main子程序结束的代码
      pop  bp
      ret
_main   endp
 _TEXT   ends                ;代码段的结束
 _DATA   segment word public 'DATA'    ;数据段的定义
      s@ label byte
         db '%d'
         db 0
_DATA   ends
 public  _main           ;下面说明函数的属性,请见第7.6.3节
public  @sum$qiii
extrn  _printf : near
_s@  equ s@
end
 12.3 简单的屏幕编辑程序
下面是一个简单的屏幕编辑的C语言程序,它不仅涉及到键盘处理、光标定位、屏幕输出、字符颜色等,而且还运用了C语言和汇编语言的混合编程方法。若读者能把它改写成相同功能的汇编语言程序,那么,可以说,你已基本掌握了中断的使用方法,也对计算机输入输出的工作方式有了更进一步的认识。

该程序的功能:
◆ 可用移动光标键↑、↓、←和→移动光标1行或1列,也可用TAB/Shift+TAB、Home和End键跳跃地移动光标;
◆ 当光标已在第1行,再向上移动时,这时,光标被定位到第25行,反之也然;
◆ 当光标已在第0列,还要向左移动时,光标被定位到第79列,反之也然;
◆ 当按下^W或^Z时,屏幕将向上或向下滚动1行;
◆ 显示当前键盘的状态:大小写状态、数字键盘状态和插入/修改状态;
◆ 如果按普通的键,将在屏幕上显示该字符,如果按下用Alt、Ctrl或Shift组合的组合键,则显示该按键的扫描码;
◆ 用Esc键来结束程序的运行。

C语言的源程序清单:

#define NUM_KEY 0x20      /* 键盘状态字宏定义 */
#define CAPS_KEY 0x40
#define ESCAPE 27        /* 几个功能键的宏定义 */
#define TAB_KEY 9
#define SHIFT_TAB 15
#define CTRL_W 23
#define CTRL_Z 26
#define UP_ARROW 72
#define DOWN_ARROW 80
#define LEFT_ARROW 75
#define RIGHT_ARROW 77
#define INSERT 82
#define END_KEY 79
#define HOME_KEY 71
#define UP_SCROLL 6      /* 屏幕滚动宏定义 */
#define DOWN_SCROLL 7

#include <dos.h>
int insert, cap_key, num_key;

/* up_down:屏幕滚动方式:6-向上滚; 7-向下滚
 (l_row, l_col)-(r_row, r_col):滚动矩形的对角线坐标
 num:屏幕滚动的行数,0-清屏
 attr:滚动后所剩下行的属性 */
cls(int up_down, int l_row, int l_col, int r_row, int r_col, int num, int attr)

{union REGS in, out;

 in.h.ah = up_down; in.h.al = num;
 in.h.ch = l_row;   in.h.cl = l_col;
 in.h.dh = r_row;   in.h.dl = r_col;
 in.h.bh = attr;
 int86(0x10, &in, &out);
}

  get_cursor(int *x, int *y)  /* 取当前光标的位置,并分别存入变量x和y中 */

{union REGS in, out;

 in.h.ah = 3; in.h.bh = 0;
 int86(0x10, &in, &out);
 *x = out.h.dh; *y = out.h.dl;
}

  locate(int row, int col)  /* 把光标设置在(row, col)位置 */

{union REGS in, out;

 in.h.ah = 2;  in.h.bh = 0;
 in.h.dh = row; in.h.dl = col;
 int86(0x10, &in, &out);
}

  disp_string(int row, int col, char string[])  /* 在(row, col)位置显示字符串string */

{struct REGPACK in, out;
 int x, y;

 get_cursor(&x, &y);
 locate(row, col);
 in.r_ds = FP_SEG(string); in.r_dx = FP_OFF(string); in.r_ax = 0x900; intr(0x21, &in);
 locate(x, y);
}

  check_key_state()  /* 在(row, col)位置以属性attr显示字符ch */

{char state;

 state = bioskey(2);
 if (state & CAPS_KEY)
  {if (!cap_key) {cap_key = 1; disp_string(24, 66, "CAP$");}
  }
else if (cap_key) {cap_key = 0; disp_string(24, 66, " $");}
if (state & NUM_KEY)
 {if (!num_key) {num_key = 1; disp_string(24, 70, "NUM$");}
 }
else if (num_key) {num_key = 0; disp_string(24, 70, " $");}
}

  insert_key()  /* 在最后一行显示插入/修改状态标志,并改变光标形状 */

{union REGS in, out;

 insert = 1 - insert;
 disp_string(24, 74, (insert ? "INS$" : " $"));  /* 显示插入/修改标志 */
 in.h.ah = 1;
 in.h.ch = (insert ? 0 : 14); in.h.cl = 15;    /* 改变光标的形状 */
 int86(0x10, &in, &out);
}

  move_right(int row, int col, int len)  /* 在(row, col)位置之后的字符和属性向后移len个位置 */

{int j, attr;
 char ch;

 for (j = 79; j >= col+len; j--)
  {read_char_attr(row, j-len, &ch, &attr);
   write_char_attr(row, j, ch, attr);
  }
}

  read_char_attr(int row, int col, char *ch, int *attr)  /* 在读(row, col)位置字符和属性,并分别存入ch和attr */

{union REGS in, out;

 locate(i, j);
 in.h.ah = 8; in.h.bh = 0;
 int86(0x10, &in, &out);
 *ch = out.h.al; *attr = out.h.ah;
}

  write_char_attr(int row, int col, char ch, int attr)  /* 在(row, col)位置以属性attr显示字符ch */

{union REGS in, out;

 locate(row, col);
 in.h.ah = 9; in.h.al = ch;
 in.h.bh = 0; in.h.bl = attr; in.x.cx = 1;
 int86(0x10, &in, &out);
}

  ctos(char ascii, char str[])  /* 把字符的ASCII码转换成字符串 */

{int i;

 i = 2;
 do {str[i--] = ascii%10 + '0';
  ascii /= 10;
 } while (ascii > 0);
 for (; i >= 0; i--) str[i] = ' ';
}

main()
{int k, key, row, col;
 char ch1, ch2, str[]=" $";   /* 前面有3个空格 */
 char msg1[]="This is a simple screen edidtor.$",
 msg2[]="You can move cursor by Arrow keys, TAB/Shift-TAB, Home and End.$",
 msg3[]="You can press ^W for scroll up or ^Z for scroll down.$",
 msg4[]="It has some functions, such as insert/modify a char.$",
 msg5[]="If you press a function key, or key combined with Alt, Ctrl, Shift, it will display the key's scan code.$",
 msg6[]="The program exits when you press ESCAPE.$";

cls(UP_SCROLL, 0, 0, 24, 79, 0, 7);
disp_string(0, 0, msg1); disp_string(2, 0, msg2);
disp_string(4, 0, msg3); disp_string(6, 0, msg4);
disp_string(8, 0, msg5); disp_string(11, 0, msg6);
row = col = ch1 = insert = 0;
locate(row, col);

while (ch1 != ESCAPE)
 {while (ch1 != ESCAPE)
  {if (!bioskey(1)) {check_key_state(); continue;}
   key = bioskey(0);
   ch1 = key; ch2 = key >> 8;
   if (ch1 != 0)
    {switch(ch1)
    {case TAB_KEY:
        col = ((col&0xFFF8) + 8) %80;
        break;
    case CTRL_W:
       cls(DOWN_SCROLL, 0, 0, 24, 79, 1, 7);
       row = row + 1;
       break;
    case CTRL_Z:
       cls(UP_SCROLL, 0, 0, 24, 79, 1, 7);
       break;
    default:
       if (ch1 == ESCAPE) continue;
       if (insert) move_right(row, col, 1);
       write_char_attr(row, col, ch1, 31);
       col = (col+1+80) % 80;
       break;
   }
   locate(row, col);
   continue;
   }

switch (ch2)
 {case UP_ARROW:
    row = (row-1+25) % 25;
    break;
  case DOWN_ARROW:
    row = (row+1+25) % 25;
    break;
  case LEFT_ARROW:
    col = (col-1+80) % 80;
    break;
  case RIGHT_ARROW:
    col = (col+1+80) % 80;
    break;
  case SHIFT_TAB:
    k = col & 0xFFF8;
    col = (col - ((k==0)? 8:k+80)) % 80;
    break;
  case HOME_KEY:
    col = 0;
    break;
  case END_KEY:
    col = 79;
    break;
  case INSERT:
    insert_key(&insert);
    break;
  default:
    ctos(ch2, str);
    k = strlen(str)-1;
    if (insert) move_right(row, col, k);
    disp_string(row, col, str);
    col = (col + k + 80) % 80;
    break;
 }

  locate(row, col);
  }
 }
 cls(UP_SCROLL, 0, 0, 24, 79, 0, 7);
}
12.4 习题
12.1、把12.3节中的C语言程序改写成汇编语言程序。
 
12.2、编写C语言程序,输出下面表达式的值,要求该表达式的计算用嵌入汇编语言程序段的方法来实现(注:题中所有变量都是整型)。
 
1)、1230 + 'A' - a
2)、b * b – 4 * a * c
3)、(a + b) / c + d
 4)、9*c / 5 + 32
5)、(a % 9 + 89) * 8
6)、x * x + y * y
12.3、用汇编语言编写函数Display(Data),其功能是在当前光标处显示无符号整数Data,然后,编写一个C语言程序调用Display来显示整型变量的值。
 
12.4、用汇编语言实现下列C语言标准函数,并在C语言程序中验证之(假设未指明的变量都是整型)。
 
1)、isalpha(int Ascii) /*若Ascii是字母的Ascii码,则其函数值为真,否则为假*/
 
2)、isxdigit(int Ascii)
/*若Ascii是十六进制字符('0'~'9'、'A'~'F'和'a'~'f'),那么,其函数值为真,否则为假*/
 
3)、strlwr(char *s) /*把字符串s中的字母转换成小写*/
 
4)、strchr(char *s1, int Ascii)
/*在字符串s1中查找是否存在字符Ascii。若不存在,则返回NULL(即0),否则,返回指向该字符在字符串中位置的指针*/
 
5)、strncmp(char *s1, char *s2, int Len)
/*比较字符串s1和s2前Len个字符,若s1<s2,其值小于0;s1==s2,其值为0;否则,其值大于0*/
 
6)、strncpy(char *Dest, char *Src, int Len) /*把Src串中前Len个字符拷贝到Dest中*/
 
7)、memset(void *Buff, int Data, int Len)  /*把用Data填充Buff前Len个存储单元*/
 
12.5、编写一个C语言程序,用TCC/BCC命令生成汇编语言程序,分析C语言语句和汇编语言语句之间的实现关系。
 
12.6、编写一个C语言程序,求出2~100之内的所有素数(大于1,且只能被1和自身整除的数,称为素数),然后把它改写汇编语言程序,并比较二者代码的。
 
12.7、编写一个C语言程序,求出2~999之内的所有能被9整除,且含有5的数,然后把它改写汇编语言程序。
 
12.8、用汇编语言编写一个过程Display(Data),其功能为在当前光标处显示无符号整数Data,然后编写C语言程序调用之,以达到显示数据的作用。
 
2011-07-15 21:01
zklhp
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:china
等 级:贵宾
威 望:254
帖 子:11485
专家分:33241
注 册:2007-7-10
收藏
得分:0 
大概看了这个 应该没问题了

参数顺序 自右向左压栈

C调用规范支持可变参数 由调用者恢复堆栈 也就是add esp,n

所谓的调用 就是混合编译罢 核心就在怎么把你写的东西和已经有的库合到一块 这个罢 因为不知道你是什么环境 没法详细说 不过大概意思上面已经有了
2011-07-15 21:08
zjsxwc
Rank: 7Rank: 7Rank: 7
等 级:黑侠
威 望:1
帖 子:252
专家分:601
注 册:2011-1-20
收藏
得分:0 
回复 3楼 zklhp
没看到

The tools I recommended:
GUI: CSharp(VS), QT;    Core Code: Plain C (Tiny C Compiler);    Web: Python, JavaScript;    Android: Java;    Embedded System: ASM&C (Linux)
2011-07-15 21:37
zklhp
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:china
等 级:贵宾
威 望:254
帖 子:11485
专家分:33241
注 册:2007-7-10
收藏
得分:0 
要是win32汇编我能给例子 16位的我就不会了。。
2011-07-15 22:32
zjsxwc
Rank: 7Rank: 7Rank: 7
等 级:黑侠
威 望:1
帖 子:252
专家分:601
注 册:2011-1-20
收藏
得分:0 
回复 5楼 zklhp
好吧换种方式问,怎么用c访问寄存器eax,把eax的值赋给c中定义的一个变量,有具体程序段吗?

The tools I recommended:
GUI: CSharp(VS), QT;    Core Code: Plain C (Tiny C Compiler);    Web: Python, JavaScript;    Android: Java;    Embedded System: ASM&C (Linux)
2011-07-17 07:50
zklhp
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:china
等 级:贵宾
威 望:254
帖 子:11485
专家分:33241
注 册:2007-7-10
收藏
得分:100 
以下是引用zjsxwc在2011-7-17 07:50:52的发言:

好吧换种方式问,怎么用c访问寄存器eax,把eax的值赋给c中定义的一个变量,有具体程序段吗?

内联汇编

但内联汇编的限制是很大的 Win32环境倒是下可以用

gcc的语法复杂你自己查好了。。

VC的语法是__asm 于是 就是 __asm i,eax
2011-07-17 07:59
zjsxwc
Rank: 7Rank: 7Rank: 7
等 级:黑侠
威 望:1
帖 子:252
专家分:601
注 册:2011-1-20
收藏
得分:0 
回复 7楼 zklhp
好吧,谢谢斑竹

The tools I recommended:
GUI: CSharp(VS), QT;    Core Code: Plain C (Tiny C Compiler);    Web: Python, JavaScript;    Android: Java;    Embedded System: ASM&C (Linux)
2011-07-17 18:25
快速回复:菜鸟请教 ,怎么用汇编调用C函数,怎么用C调用汇编写的函数,他们的参 ...
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.032101 second(s), 7 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved