zoukankan      html  css  js  c++  java
  • 在c语言中嵌入汇编语句,对于我来说相当难。

    今天早上在csdn论坛上看到一个帖子http://topic.csdn.net/u/20120917/14/82f42e17-977a-4824-95bd-7b79db15d283.html:“C语言中嵌入汇编,究竟有何意义?”

    其中看到一个例子是在c语言中插入一段汇编代码获取CPU的主频,制造商和型号的:

    //=====================================================================================
    /*                 CPUID指令是intel IA32架构下获得CPU信息的汇编指令,
                       可以得到CPU类型,型号,制造商信息,商标信息,序列号,
                       缓存等一系列CPU相关的东西。
    */
    #include <windows.h>
    #include <iostream>
    #include <string>

    using namespace std;


    //用来存储eax,ebx,ecx,edx四个寄存器的信息
    DWORD deax;
    DWORD debx;
    DWORD decx;
    DWORD dedx;

    void ExeCPUID(DWORD veax)  //初始化CPU
    {
    __asm
    {
        mov eax,veax
        cpuid
        mov deax,eax
        mov debx,ebx
        mov decx,ecx
        mov dedx,edx
    }
    }

    /*    在Intel Pentium以上级别的CPU中,有一个称为“时间戳(Time Stamp)”的部件,
        它以64位无符号整型数的格式,记录了自CPU上电以来所经过的时钟周期数。
        由于目前的CPU主频都非常高,因此这个部件可以达到纳秒级的计时精度。
        这个精确性是上述两种方法所无法比拟的。
        在Pentium以上的CPU中,提供了一条机器指令RDTSC(Read Time Stamp Counter)
        来读取这个时间戳的数字,并将其保存在EDX:EAX寄存器对中
    */
    long GetCPUFreq()       //获取CPU频率,单位: MHZ
    {
        int start,over;
        _asm 
        {
            RDTSC
            mov start,eax
        }
        Sleep(50);
        _asm 
        {
            RDTSC
            mov over,eax
        }
        return (over-start)/50000;
    }

    /*   把eax = 0作为输入参数,可以得到CPU的制造商信息。
         cpuid指令执行以后,会返回一个12字符的制造商信息,
         前四个字符的ASC码按低位到高位放在ebx,中间四个放在edx,最后四个字符放在ecx。
    */
    string GetManID()   //获取制造商信息
    {
        char ID[25];        
        memset(ID,0,sizeof(ID));
        
        ExeCPUID(0);          //初始化
        memcpy(ID+0,&debx,4); //制造商信息复制到数组
        memcpy(ID+4,&dedx,4);
        memcpy(ID+8,&decx,4);
        
        return string(ID);
    }


    /*  在我的电脑上点击右键,选择属性,可以在窗口的下面看到一条CPU的信息,
        这就是CPU的商标字符串。CPU的商标字符串也是通过cpuid得到的。
        由于商标的字符串很长(48个字符),所以不能在一次cpuid指令执行时全部得到,
        所以intel把它分成了3个操作,eax的输入参数分别是0x80000002,0x80000003,0x80000004,
        每次返回的16个字符,按照从低位到高位的顺序依次放在eax, ebx, ecx, edx。
        因此,可以用循环的方式,每次执行完以后保存结果,然后执行下一次cpuid。
    */
    string GetCPUType()
    {
        const DWORD id = 0x80000002; //从0x80000002开始,到0x80000004结束
        char CPUType[49];//用来存储CPU型号信息
        memset(CPUType,0,sizeof(CPUType));//初始化数组
        
        for(DWORD t = 0 ; t < 3 ; t++ )
        {
            ExeCPUID(id+t);
            //每次循环结束,保存信息到数组
            memcpy(CPUType+16*t+ 0,&deax,4);
            memcpy(CPUType+16*t+ 4,&debx,4);
            memcpy(CPUType+16*t+ 8,&decx,4);
            memcpy(CPUType+16*t+12,&dedx,4);
        }
        
        return string(CPUType);
    }

    void main() 

        cout<<"本机CPU信息如下:"<<endl;
        cout<<"CPU 主 频: "<<GetCPUFreq()<<" MHZ"<<endl;
        cout<<"CPU 制造商: "<<GetManID()<<endl;
        cout<<"CPU 型 号: "<<GetCPUType()<<endl;
        cin.get();

    }

    顿时来了兴趣,这个例子是用c++语法写的,我打开CodeBlocks简单的改了几处地方就变成c了,然后编译,出现了一大堆的错误。

    经过一个多小时的探索,首先搞明白了,在CodeBlocks + GCC里可以嵌入汇编语句,这是肯定的。

    因为我在网上找到了一个简单的例子:

    #include <stdio.h>

    //这个是vc6下面的写法

    /*

    int sum(int a,int b)
    {
    __asm
    {
    mov eax, [ebp+8]
    add eax, [ebp+0Ch]
    }
    }

    */

    //这个是gcc下面的写法

    int sum(int a, int b)
    {
        __asm__
        (
            "movl 8(%ebp), %eax;"
            "addl 12(%ebp), %eax;"
        );
    }


    int main()
    {
        printf("1 + 2 = %d ", sum(1,2));

        return 0;
    }

    程序能正常的编译和执行。

    但为什么那个获取CPU信息的代码编译时老是提示:

    too   many   memory   references   for   mov 

    后来又找到这么一篇:http://topic.csdn.net/u/20070416/13/82e4047a-c812-43d4-a28e-e67ddf6c9ad6.html

    网友主要提示:

    你应该先学习一下ATT语法。 
    __asm__   ( "subl   %0,   %%esp "   :   : "m "(paramnumber)); 
    __asm__   ( "movl   %0,   %%ecx "   :   : "m "(paramnumber)); 
    __asm__   ( "movl   %0,   %%esi "   :   : "m "(parameters)); 
    __asm__   ( "movl   %esp,   %edi "); 
    __asm__   ( "rep   movsb "); 

    看到这个,我打算放弃改写了,这个ATT语法看着头大,不打算再搞了。

    如果将来哪天需要用到,再从头学起吧。

    2012-09-20

  • 相关阅读:
    PTA 7-5 有趣的最近公共祖先问题 (30分)
    平衡二叉树的旋转类型及代码实现
    Ubuntu搭建青岛大学开源OJ
    见过猪跑现在开始吃猪肉了
    工作4年的老腊肉的总结
    服务器日志的目录
    Jacoco配置的问题
    一次述职之后的反省
    Python+Webdriver+Phantomjs,设置不同的User-Agent,获得的url不一致
    Eclipse+Pydev 找不到对应的module not in Pythonpath
  • 原文地址:https://www.cnblogs.com/personnel/p/4584820.html
Copyright © 2011-2022 走看看