免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 4389 | 回复: 7
打印 上一主题 下一主题

在C语言里嵌入汇编语言的问题??? [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2003-11-28 12:58 |只看该作者 |倒序浏览
1.c语言里有个关于汇编语言的宏,这个宏在linux的哪里???,名字是什么???

2.在c程序里可以嵌入一段汇编语言,那还是用gcc编译这段c程序吗???

先谢谢各位大侠了

论坛徽章:
0
2 [报告]
发表于 2003-11-28 14:04 |只看该作者

在C语言里嵌入汇编语言的问题???

我没做个,但这里有些资料,希望对你有用!摘要

  GNU C/C++编译器(GCC)是一个32-bit的编译器,是GNU计划的核心,能非常好的支持x86体系结构,它支持在C程序里面嵌入汇编代码,这样看来,寄存器可以自己指定也可以留给gcc来分配。GCC可以在多个平台下使用,除了linux,还有*BSD, VSTa, OS/2, *DOS, Win*等等。

(2002-08-25 14:26:20)

--------------------------------------------------------------------------------
By Wing, 出处:作者:luster


  2001/9/12

  3. 汇编器

  gcc内嵌编译器

  GNU C/C++编译器(GCC)是一个32-bit的编译器,是GNU计划的核心,能非常好的支持x86体系结构,它支持在C程序里面嵌入汇编代码,这样看来,寄存器可以自己指定也可以留给gcc来分配。GCC可以在多个平台下使用,除了linux,还有*BSD, VSTa, OS/2, *DOS, Win*等等。

  可以在GNU FTP站点下载GCC。链接是:

  ftp://prep.ai.mit.edu/pub/gnu/gcc/

  现在GCC已经分裂成两个分支(GCC 2.8和EGCS),但是它们又重新合并了起来,GCC的主页位于:http://gcc.gnu.org.

  因为内核头文件中定义的一些汇编例程函数都是extern inline函数,所以GCC必须要加-O(或者-O2,-O3等)编译标志,这样才能使得这些函数可以使用。否则,如果不加-O标志,代码也可以被编译,但是可能link会不正确。

  嵌入汇编语言可以通过“-fno-asm”来被禁止。不过通常来说,比较好的编译标志是如下的,这对于大多数的x86平台都是很不错的选择:


gcc -O2 -fomit-frame-pointer -W -Wall



  -O2在大部分情况下都是很好的代码优化级别。事实上,使用优化后会带来更多的编译时间,也会产生大一些地代码,而在速度上仅仅有一点点提高。

  -fomit-frame-pointer允许产生的代码中跳过一些错误的frame pointer maintenance,这样可以使得代码小一些而且快一些,而且会释放一些寄存器来获得更进一步的优化。

  -W –Wall使得我们可以获得很多有用的warning,这对于我们减少一些愚蠢的编码错误是非常有用的。

  我们还可以加一些编译参数来指明目标CPU的类型,这样就允许GCC来产生一些针对特定CPU的优化代码。在编译内核中使用指明CPU类型的参数是非常有用的。具体GCC支持什么类型CPU优化,我们可以参考所使用的GCC的文档。

  GCC对宏的支持

  GCC允许而且要求你指明你的嵌入汇编代码使用的寄存器,这样编译器的优化器才能知道如何优化。因此,嵌入汇编代码通常是一些patterns,而不是真正的代码(exact code)。因此,通常我们把汇编代码放到CPP的宏定义里面,或者定义成inline函数,这样就可以方便的就像使用C函数或宏一样使用这些代码。Inline函数和宏非常相似,不过inline函数比较起后者,使用起来更清晰。

  GAS

  GAS是GNU的汇编器,GCC实际上也依赖它。我们可以在任何能下载GCC的地方找到这个实用工具,它通常位于一个名叫binutils的包里面。下面的URL给出了最新的版本:

  ftp://ftp.varesearch.com/pub/support/hjl/binutils/.

  GAS是一个支持32-bit的unix环境下的汇编编译器,它使用标准的AT&T语法,它使用标准的m68k编译器的语法,这是UNIX world的标准。这个语法和Intel的语法不一样,如果你适应了这种语法,那么你就会发现它也是很好用的。下面是一些GAS语法的主要特点:

  · 所有的寄存器的名字都是以“%”最为前缀,所以可能的一些寄存器是%eax,%dl等等,而不是简单的eax,dl等。这样的话可以使得C语言中方便的嵌入一些汇编代码而不会有变量名字方面冲突的担心。

  · 操作数的顺序也是相反的。例如要把edx寄存器的内容拷贝到eax寄存器里面的话,GAS的语法是:mov %edx,%eax;而Intel平台下的汇编语句是:mov eax,edx。

  · 操作数的尺寸作为一个后缀加在操作名的后面。B表示(8-bit)byte,w表示(16-bit) word,l表示(32-bit) long。例如,上面例子中正确的语法应该是:movl %edx,%eax。不过,GAS并不需要严格的AT&T语法,所以这个后缀可可以省略的,这时候编译器就自己根据操作数判断或者置为缺省的位宽32-bit。

  · 立即数需要一个“$”前缀符号,例如:addl $5,%eax。

  · 如果没有操作数前缀,则表示它是内存地址,例如:movl $foo,%eax,把变量foo的地址送到了%eax寄存器。但是“movl foo,%eax”则把foo变量的内容送到eax寄存器中。

  已经有一些工具可以帮助你把你的使用Intel汇编语法的源程序转换成AT&T语法,或者做相反的转换。

  不过,已经有的好消息是Binutils 2.10开始,GAS已经可以支持Intel语法了。

  16-bit mode

  摘要

  Netwide Assebler Project计划提供了一个非常好用的 i386汇编器,这个汇编器是用C写的,可以支持很多种对象文件格式。

(2002-08-25 14:28:47)

--------------------------------------------------------------------------------
By Wing, 出处:作者:luster


  今天我们接着看看还有其他什么可以选择的汇编编译器:

  NASM

  Netwide Assebler Project计划提供了一个非常好用的 i386汇编器,这个汇编器是用C写的,可以支持很多种对象文件格式。

  我们可以在下面的网址获得nasm最新的版本:

  http://nasm.2y.net, http://www.cryogen.com/nasm/

  语法还是使用的Intel方式的,集成了很好的对宏指令的支持。支持的object文件格式有:bin,a.out,coff,elf,as86,obj(DOS),win32,rdf等。NASM可以用作免费的

  LCC编译器的backend。

  除非你使用16-bit的编译器BCC,否则,你可以很好的使用NASM,而不必要去使用其他的AS86或者MASM,因为NASM在几乎所有的平台上都可以很好的运行。另外,它还有一个反汇编程序,名字叫NDISASM。

  NASM是用的是一个人工编写语法分析器,比GAS速度要快。如果你喜欢用Intel风格的语法,而不习惯GAS的语法,那么NASM是你最好的选择了。

  AS86

  AS86是一个支持80x86的汇编编译器,同时支持16-bit和32-bit,也有集成的对宏指令的支持。在寻址表示方面有点区别外,其他语法都是何Intel的语法一样的。最新的版本可以在下面的网址获得:

  http://www.cix.co.uk/~mayday/,

  下面是个例子,是一个GNU Makefile里面,使用BCC来讲.s asm文件编译成aout .o 的目标文件和 .l 的listing文件:


%.o %.l: %.s bcc -3 -G -c -A-d -A-l –A$*.l -o $*.o $<



  如果你不需要listing文件,就把“%.l,-A –l”和”-A$* .l”删除。如果你想编译成其他的东西,而不是a.out文件,那么可以修改BCC的参数。

  其他汇编器

  还有很多的可以使用的汇编器。下面列举几个,供大家参考:

  Free Pascal

  Free Pascal 集成了一个32-bit的汇编器。

  Win32Forth assembler

  Win32Forth是一个免费的32-bit的ASN FORTH系统,可以在Win32s,Win95,WinNT下正常使用。它包括了一个32-bit的汇编器,这个编译器嵌入到了FORTH语言当中了。可以在下面的站点下载:

  ftp://ftp.forth.org/pub/Forth/Compilers/native/windows/Win32For/.

  SHASM

  SHASM是用GNU Bash Version 2编写的一个汇编器,可以在其他unix-style的“shell”命令解释器下运行。可以在下面的网址下载最新版本:

  ftp://linux01.gwdg.de/pub/cLIeNUX/interim/shasm.TGZ

  TDASM

  TDASM是Table Driven Assembler的,可以对各种版本的汇编语言做交叉编译。可以到下面的网站下载:

  http://www.penguin.cz/~niki/tdasm/

  Terse

  Terse是一个编程工具,它为x86系列提供了最紧凑的汇编语法编译。详细情况参考:

  http://www.terse.com/

  HLA

  HLA 是a High Level Assembly language的缩写。它的变量声明、过程声明、过程调用等都使用高级语言类似的语法)例如使用与Pascal,C/C++类似的语法)。HLA是免费的,不过只能在Win32下面使用。访问下面的网站可以获得更多的资料:

  http://webster.cs.ucr.edu/

  TALC

  TALC 是另外一个基于MASM/Win32地免费的编译器。TAL是Typed Assembly Language的缩写。可以访问下面的网站:

  http://www.cs.cornell.edu/talc/

  待续。。。

  luster@linuxaid.com.cn

  hwang@ustc.edu



【责任编辑:风过留枫】
【关闭窗口】


相关内容   



· 无


请您评论
姓名:

论坛徽章:
0
3 [报告]
发表于 2003-11-28 14:05 |只看该作者

在C语言里嵌入汇编语言的问题???

摘要

  汇编代码编写程序是非常枯燥的,但是通常是程序的一些关键的部分. 你应该根据自己的任务选择合适的开发工具,

(2002-08-25 14:28:53)

--------------------------------------------------------------------------------
By Wing, 出处:作者:luster


  4. Metaprogramming

  汇编代码编写程序是非常枯燥的,但是通常是程序的一些关键的部分. 你应该根据自己的任务选择合适的开发工具, 如果不适合用汇编的场合最好还是别用, C, Ocaml, perl, Scheme, 都是其他可以选择使用的好的开发工具. 但是, 某些场合这些开发工具可能不能提供足够的对机器的控制能力, 此时, 汇编语言就可以发挥作用了.这些场合,你常常学要结合macroprocessing和metaprogramming. 纯粹的汇编代码通常是不够用的, 你要把自己的代码和C 语言代码link起来.

  External filters

  无论你的汇编器支持怎么样的宏,或者你使用什么样的语言(例如C), 这种语言应该对于你来说是足够清晰的,你可以在Makefile里面使用这样的规则来用一些扩展的filters来过滤你的文件:


%.s: %.S other_dependencies $(FILTER) $(FILTER_OPTIONS) < $< >; $@



  Metaprogramming

  不使用扩展的filter来展开这些宏,也可以写一些程序来产生其他的程序的一部分或者全部.

  例如,你可以使用程序来输出一些源码:

  · 产生标准的数学函数sin/cos等数学函数值查找表.

  · 将我们的bitmap图片文件快速显示的函数

  · 用自己写的perl/shell/scheme脚本来产生一些我们自己的特定的汇编代码.

  · 用程序来生产初始化和结束处理的代码,对数据表的描述代码等.

  · 等等

论坛徽章:
0
4 [报告]
发表于 2003-11-28 14:06 |只看该作者

在C语言里嵌入汇编语言的问题???

  5. 我们开始写hello world吧

  好吧,我们已经铺垫了很多东西了,而且看上去用汇编写程序似乎是一个非常恐怖的事情了。不过既然我们感兴趣,还是应该开始我们的“hello world”程序。

  下面的代码中,我们准备采取直接使用内核中的系统调用的方法,这是调用系统内核服务的最快的方法,我们的代码不链接到其他函数库,也不使用ELF解释器,而是直接和内核通讯。

  我们分别使用nasm和gas两种汇编器来编译我们的程序,这样我们可以看到Intel和AT&T两种语法格式了。

  使用的工具

  当然首先我们需要汇编编译器nasm和gas。然后我们需要链接器-ld,因为汇编编译器是生成的只是object代码。一般的发行包的binutils里面包括了gas和ld这两个实用工具。而对于大多数的发行包(例如,Debian,SuSe,Mandrake)都有nasm。


Hello, world!



  Linux是一个32位的,运行在保护模式下的操作系统,使用的是flat memory 模式,使用ELF格式的二进制代码。

  一个程序可以划分为下面几个部分: .text,.data,.bss。.text是一些只读的代码,.data是可读可写的数据区,.bss则是可读可写的没有初始化的数据区。当然可以有其他一些标准的部分,也可以使用户自己定义的sections,但是我们这里不关心。一个程序至少有.text部分。

  下面就是我们的第一个程序“hello,world”。我们给出两个版本,分别是nasm和gas两种。


NASM (hello.asm)
--------------
section .data ;section declarationmsg db "Hello, world!",
0xa ;our dear stringlen equ $ - msg ;length of our dear stringsection .text ;
section declaration ;we must export the entry point to the ELF linker
or global _start ;loader. They conventionally recognize _start as their ;
entry point. Use ld -e foo to override the default._start:;write our string
to stdout mov edx,len ;third argument: message length mov ecx,msg ;second
argument: pointer to message to write mov ebx,1 ;first argument: file handle
(stdout) mov eax,4 ;system call number (sys_write) int 0x80 ;call kernel;
and exit mov ebx,0 ;first syscall argument: exit code mov eax,1 ;system
call number (sys_exit) int 0x80 ;
call kernel
GAS (hello.S)
--------------
.data # section declarationmsg: .string "Hello, world! "
# our dear string len = . - msg # length of our dear string.text
# section declaration # we must export the entry point to the ELF linker or
.global _start # loader. They conventionally recognize _start as their
# entry point. Use ld -e foo to override the default._start:
# write our string to stdout movl $len,%edx # third argument:
message length movl $msg,%ecx # second argument: pointer to message to
write movl $1,%ebx # first argument: file handle (stdout) movl $4,%eax
# system call number (sys_write) int $0x80 # call kernel# and exit movl
$0,%ebx # first argument: exit code movl $1,%eax # system call number
(sys_exit) int $0x80 # call kernel



  建立可运行的程序

  要生成一个可执行的代码,首先就是用源代码编译生产一个object文件。

  对于nasm,下面的语法:


$ nasm -f elf hello.asm



  而对于gas,而用下面的语法:


$ as -o hello.o hello.S



  这样就得到了hello.o这个object文件了。

  然后我们就要使用这个object文件来生成可执行代码。这里使用链接器链接:


$ ld -s -o hello hello.o



  这样我们就获得了我们的可以执行的代码“hello,world”。

  我们的学习就告一段落了。更多的信息可以去参考:

  http://linuxassembly.org/list

  by Luster(luster@linuxaid.com.cn)

  2001/9/21

论坛徽章:
0
5 [报告]
发表于 2003-11-28 15:11 |只看该作者

在C语言里嵌入汇编语言的问题???

谢谢!!!
不过我想要关于linux下的汇编指令有哪些???
采用什么语法格式???
再有一些简单的范列就好了(就是在一段C程序里嵌入汇编语句)!!!
麻烦各位了

论坛徽章:
0
6 [报告]
发表于 2003-11-28 16:14 |只看该作者

在C语言里嵌入汇编语言的问题???

Introduction

  The following is designed to be a Linux equivalent to "Developing Assembly Language Programs on a PC" by Douglas V. Hall. This tutorial requires the following:

  an i386 family PC running Linux

  as, the GNU assembler (included with any gcc installation) ld, the GNU linker (also included with gcc) gdb, the GNU debugger The tutorial was developed on a 5.1 Redhat Linux installation running a 2.0.34 version kernel and the version 5 and 6 C language libraries with ELF file format. But I have tried to make the tutorial as general possible with respect to Linux systems. I highly recommend working through this tutorial with "as" and "gdb" documentation close at hand.

  Overview

  The process of developing an assembly program under linux is somewhat different from development under NT. In order to accommodate object oriented languages which require the compiler to create constructor and destructor methods which execute before and after the execution of "main", the GNU development model embeds user code within a wrapper of system code. In other words, the user's "main" is treated as a function call. An advantage of this is that user is not required to initialize segment registers, though user code must obey some function requirements.

  The Code

  The following is the Linux version of the average temperature program. It will be referred to as "average.s". Note: Assembly language programs should use the ".s" suffix.


-----------------------------------------------------------
/* linux version of AVTEMP.ASM CS 200, fall 1998 */
.data   /* beginning of data segment */
/* hi_temp data item */
        .type hi_temp,@object  /* declare as data object */
        .size hi_temp,1         /* declare size in bytes */
hi_temp:
        .byte 0x92      /* set value */
/* lo_temp data item */
        .type lo_temp,@object
        .size lo_temp,1
lo_temp:
        .byte 0x52
/* av_temp data item */
        .type av_temp,@object
        .size av_temp,1
av_temp:
        .byte 0
/* segment registers set up by linked code */
/* beginning of text(code) segment */
.text
        .align 4        /* set 4 double-word alignment */
.globl main             /* make main global for linker */
        .type main,@function    /* declare main as a function */
main:
        pushl %ebp /* function requirement */
        movl %esp,%ebp /* function requirement */
        movb hi_temp,%al
        addb lo_temp,%al
        movb $0,%ah
        adcb $0,%ah
        movb $2,%bl
        idivb %bl
        movb %al,av_temp
        leave /* function requirement */
        ret /* function requirement */
--------------------------------------------------------------



  assembly instructions

  This code may be assembled with the following command:


as -a --gstabs -o average.o average.s



  The "-a" option prints a memory listing during assembly. This output gives the location variables and code with respect to the beginnings of the data and code segments. "--gstabs" places debugging information in the executable (used by gdb). "-o" specifies average.o as the output file name (the default is a.out, which is confusing since the file is not executable.)

  The object file (average.o) can then be linked to the Linux wrapper code in order to create an executable. These files are crt1.o, crti.o and crtn.o. crt1.o and crti.o provide initialization code and crtn.o does cleanup. These should all be located in "/usr/lib" be may be elsewere on some systems. They, and their source, might be located by executing the following find command:

  find / -name "crt*" -print

  The link command is the following:


ld -m elf_i386 -static /usr/lib/crt1.o /usr/lib/crti.o
-lc average.o /usr/lib/crtn.o



  "-m elf_i386" instructs the linker to use the ELF file format. "-static" cause static rather than dynamic linking to occur. And "-lc" links in the standard c libraries (libc.a). It might be necessary to include "-I/libdirectory" in the invocation for ld to find the c library.

  It will be necessary to change the mode of the resulting object file with "chmod +x ./a.out".

  It should now be possible to execute the file. But, of course, there will be no output.

  I recommend placing the above commands in a makefile .

  debugging

  The "--gstabs" option given to the assembler allows the assembly program to be debugged under gdb. The first step is to invoke gdb:

  gdb ./a.out

  gdb should start with the following message:


[bjorn@pomade src]$ gdb ./a.out



  GNU gdb 4.17

  Copyright 1998 Free Software Foundation, Inc.GDB is free software, covered by the GNU General Public License, and you are

  welcome to change it and/or distribute copies of it under certain conditions.Type "show copying" to see the conditions.

  There is absolutely no warranty for GDB. Type "show warranty" for details.

  This GDB was configured as "i386-redhat-linux"...

  (gdb)

  The "l" command will list the program sourcecode.

  (gdb) l


1       /* linux version of AVTEMP.ASM CS 200, fall 1998 */
2       .data   /* beginning of data segment */
3
4       /* hi_temp data item */
5               .type hi_temp,@object  /* declare as data object */
6               .size hi_temp,1         /* declare size in bytes */
7       hi_temp:
8               .byte 0x92      /* set value */
9
10      /* lo_temp data item */
(gdb)



  The first thing to do is set a breakpoint so it will be possible to step through the code.


(gdb) break main
Breakpoint 1 at 0x80480f7
(gdb)



  This sets a breakpoint at the beginning of main. Now run the program.


(gdb) run
Starting program: /home/bjorn/src/./a.out
Breakpoint 1, main () at average.s:31
31              movb hi_temp,%al
Current language:  auto; currently asm
(gdb)



  values in registers can be checked with either "info registers"


(gdb) info registers
eax            0x8059200        134582784
ecx            0xbffffd94       -1073742444
edx            0x0      0
ebx            0x8097bf0        134839280
esp            0xbffffdd8       0xbffffdd8
ebp            0xbffffdd8       0xbffffdd8
esi            0x1      1
edi            0x8097088        134836360
eip            0x80480f7        0x80480f7
eflags         0x246    582
cs             0x23     35
ss             0x2b     43
ds             0x2b     43
es             0x2b     43
fs             0x2b     43
gs             0x2b     43
(gdb)



  ...or "p/x $eax" which prints the value in the EAX register in hex. The "e"in front of the register name indicates a 32 bit register. The Intel x86 family has included "extended" 32 bit registers since the 80386. These E registers are to the X registers as the L and H are to the X registers.Linux also uses a "flat" and protected memory model rather that segmentation,thus the EIP stores the entire current address.


(gdb) p/x $eax
$4 = 0x8059200
(gdb)



  The "p" command prints, "/x" indicates the output should be in hexadecimal.

  type "s" or "step" to step to the next instruction.


(gdb) step
32              addb lo_temp,%al
(gdb)



  notice that 92H has been loaded into the least significant bit of the EAX register (ie. the AL register) by the movb instruction.


(gdb) p/x $eax
$6 = 0x8059292
(gdb)



  And we continue stepping through the program....


(gdb) s
33              movb $0,%ah
(gdb) s
34              adcb $0,%ah
(gdb) s
35              movb $2,%bl
(gdb) s
36              idivb %bl
(gdb) s
37              movb %al,av_temp
(gdb) s
38              leave



  and if we examine the EAX register and the variable av_temp after the final movb instruction, we see that they are set to the correct value, 72H.


(gdb) p/x $eax
$9 = 0x8050072
(gdb) p/x av_temp
$10 = 0x72
(gdb)



  Note that during stepping the listed instruction is the one about to be executed.

论坛徽章:
0
7 [报告]
发表于 2003-11-28 18:25 |只看该作者

在C语言里嵌入汇编语言的问题???

我用C++写了个程序叫test.cpp
编译时: g++ -S test.cpp  得到一个文件 test.s
又    ; g++ -c test.cpp  得到一个文件 test.o
问题:
     1.用as可以将test.s编译最终得到一个可执行文件吗??? how???
     2.用ld可以将test.o变成一个可执行文件吗??? how???
在C程序里加入一段汇编码,应怎么做???
是不是要include什么???或调用什么宏或函数什么的???
或者是这样:  
               __asm
               {  
                 汇编码           
               }

盼指点迷津!!!

论坛徽章:
0
8 [报告]
发表于 2003-11-29 09:33 |只看该作者

在C语言里嵌入汇编语言的问题???

help
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP