关于C99标准在keilMDK中实验引发的,ADR指令认识,ARM寄存器之R12,及C89,C90,C95,C99标准的区别

来源:互联网 发布:ubuntu完全卸载wine 编辑:程序博客网 时间:2024/04/30 13:27
本次实验的起源是这样的:
看到C99标准里面支持变量用到时再定义,然后做了以下实验,定义函数,看反汇编结果。
void test_c99(void)
{
     char i=0;
     printf("i=%d", i);

     char j=0;
     printf("j=%d", j);

     char k=0;
     printf("k=%d", k);

     char l=0;
     printf("l=%d", l);

     char m=0;
     printf("m=%d", m);

     char n=0;
     printf("n=%d", n);

     char o=0;
     printf("o=%d", o);
    
     char p=0;
     printf("p=%d", p);

     char q=0;
     printf("q=%d", q);

     char r=0;
     printf("r=%d", r);

     char s=0;
     printf("s=%d", s);

     char t=0;
     printf("t=%d", t);

     char str[3]="Jim";
     printf("str=%s", str);
}
test_c99
          0x70007724:    e92d5fff    ._-.    PUSH     {r0-r12,lr}
          0x70007728:    e3a04000    .@..    MOV      r4,#0           //从R4寄存器开始使用,每定义一个变量使用一个寄存器
          0x7000772c:    e1a01004    ....    MOV      r1,r4               //将刚刚定义并初始化的变量(r4中)取出,放到r1中
          0x70007730:    e28f0fce    ....    ADR      r0,{pc}+0x340 ; 0x70007a70     //取出"i=%d"字符串的地址到r0中
          0x70007734:    fa00027f    ....    BLX      __2printf ; 0x70008138               //调用printf函数,函数调用的传参规则是:func(r0,r1,r2,r3) 
                                                                                                                   //具体要看ABI规范或Procedure Call Standard for ARM
          0x70007738:    e3a05000    .P..    MOV      r5,#0
          0x7000773c:    e1a01005    ....    MOV      r1,r5
          0x70007740:    e28f0e33    3...    ADR      r0,{pc}+0x338 ; 0x70007a78
          0x70007744:    fa00027b    {...    BLX      __2printf ; 0x70008138
          0x70007748:    e3a06000    .`..    MOV      r6,#0
          0x7000774c:    e1a01006    ....    MOV      r1,r6
          0x70007750:    e28f0fca    ....    ADR      r0,{pc}+0x330 ; 0x70007a80
          0x70007754:    fa000277    w...    BLX      __2printf ; 0x70008138
          0x70007758:    e3a07000    .p..    MOV      r7,#0
          0x7000775c:    e1a01007    ....    MOV      r1,r7
          0x70007760:    e28f0e32    2...    ADR      r0,{pc}+0x328 ; 0x70007a88
          0x70007764:    fa000273    s...    BLX      __2printf ; 0x70008138
          0x70007768:    e3a08000    ....    MOV      r8,#0
          0x7000776c:    e1a01008    ....    MOV      r1,r8
          0x70007770:    e28f0fc6    ....    ADR      r0,{pc}+0x320 ; 0x70007a90
          0x70007774:    fa00026f    o...    BLX      __2printf ; 0x70008138
          0x70007778:    e3a09000    ....    MOV      r9,#0
          0x7000777c:    e1a01009    ....    MOV      r1,r9
          0x70007780:    e28f0e31    1...    ADR      r0,{pc}+0x318 ; 0x70007a98
          0x70007784:    fa00026b    k...    BLX      __2printf ; 0x70008138
          0x70007788:    e3a0a000    ....    MOV      r10,#0
          0x7000778c:    e1a0100a    ....    MOV      r1,r10
          0x70007790:    e28f0fc2    ....    ADR      r0,{pc}+0x310 ; 0x70007aa0
          0x70007794:    fa000267    g...    BLX      __2printf ; 0x70008138
          0x70007798:    e3a0b000    ....    MOV      r11,#0                                   //寄存器r11中存放定义的新变量
          0x7000779c:    e1a0100b    ....    MOV      r1,r11                              
          0x700077a0:    e28f0c03    ....    ADR      r0,{pc}+0x308 ; 0x70007aa8
          0x700077a4:    fa000263    c...    BLX      __2printf ; 0x70008138
          0x700077a8:    e3a00000    ....    MOV      r0,#0                                       //寄存器已经不够用了,需要通过堆栈来存储新定义的变量。
                                                                                                                        //r12之后有特殊用途,具体看架构手册或Procedure Call Standard for ARM
                                                                                                                        //gooogleman博客有篇 arm中r12(IP)的用途
          0x700077ac:    e58d000c    ....    STR      r0,[sp,#0xc]
          0x700077b0:    e28f0fbe    ....    ADR      r0,{pc}+0x300 ; 0x70007ab0
          0x700077b4:    e59d100c    ....    LDR      r1,[sp,#0xc]
          0x700077b8:    fa00025e    ^...    BLX      __2printf ; 0x70008138
          0x700077bc:    e3a00000    ....    MOV      r0,#0
          0x700077c0:    e58d0008    ....    STR      r0,[sp,#8]
          0x700077c4:    e28f0fbb    ....    ADR      r0,{pc}+0x2f4 ; 0x70007ab8
          0x700077c8:    e59d1008    ....    LDR      r1,[sp,#8]
          0x700077cc:    fa000259    Y...    BLX      __2printf ; 0x70008138
          0x700077d0:    e3a00000    ....    MOV      r0,#0
          0x700077d4:    e58d0004    ....    STR      r0,[sp,#4]
          0x700077d8:    e28f0e2e    ....    ADR      r0,{pc}+0x2e8 ; 0x70007ac0
          0x700077dc:    e59d1004    ....    LDR      r1,[sp,#4]
          0x700077e0:    fa000254    T...    BLX      __2printf ; 0x70008138
          0x700077e4:    e3a00000    ....    MOV      r0,#0
          0x700077e8:    e58d0000    ....    STR      r0,[sp,#0]
          0x700077ec:    e28f0fb5    ....    ADR      r0,{pc}+0x2dc ; 0x70007ac8
          0x700077f0:    e59d1000    ....    LDR      r1,[sp,#0]
          0x700077f4:    fa00024f    O...    BLX      __2printf ; 0x70008138
          0x700077f8:    e8bd9fff    ....    POP      {r0-r12,pc}

$d                                                                                                              //这里是常量表区
    0x70007a40:    202d492d    -I-     DCD    539838765
    0x70007a44:    5049752d    -uIP    DCD    1346991405
    0x70007a48:    7325202d    - %s    DCD    1931812909
    0x70007a4c:    00000d0a    ....    DCD    3338
    0x70007a50:    41203a50    P: A    DCD    1092631120
    0x70007a54:    49205050    PP I    DCD    1226854480
    0x70007a58:    2074696e    nit     DCD    544500078
    0x70007a5c:    202e2e2e    ...     DCD    539897390
    0x70007a60:    00000000    ....    DCD    0
    0x70007a64:    73626577    webs    DCD    1935828343
    0x70007a68:    65767265    erve    DCD    1702261349
    0x70007a6c:    000d0a72    r...    DCD    854642
    0x70007a70:    64253d69    i=%d    DCD    1680162153
    0x70007a74:    00000000    ....    DCD    0
    0x70007a78:    64253d6a    j=%d    DCD    1680162154
    0x70007a7c:    00000000    ....    DCD    0
    0x70007a80:    64253d6b    k=%d    DCD    1680162155
    0x70007a84:    00000000    ....    DCD    0
    0x70007a88:    64253d6c    l=%d    DCD    1680162156
    0x70007a8c:    00000000    ....    DCD    0
    0x70007a90:    64253d6d    m=%d    DCD    1680162157
    0x70007a94:    00000000    ....    DCD    0
    0x70007a98:    64253d6e    n=%d    DCD    1680162158
    0x70007a9c:    00000000    ....    DCD    0
    0x70007aa0:    64253d6f    o=%d    DCD    1680162159
    0x70007aa4:    00000000    ....    DCD    0
    0x70007aa8:    64253d70    p=%d    DCD    1680162160
    0x70007aac:    00000000    ....    DCD    0
    0x70007ab0:    64253d71    q=%d    DCD    1680162161
    0x70007ab4:    00000000    ....    DCD    0
    0x70007ab8:    64253d72    r=%d    DCD    1680162162
    0x70007abc:    00000000    ....    DCD    0
    0x70007ac0:    64253d73    s=%d    DCD    1680162163
    0x70007ac4:    00000000    ....    DCD    0
    0x70007ac8:    64253d74    t=%d    DCD    1680162164
从反汇编中可以看到,很多ADR指令,这里截取一条分析
          0x70007770:    e28f0fc6    ....    ADR      r0,{pc}+0x320 ; 0x70007a90
原来以为{pc}表示的是pc+8。后来看了ADR的指令解释才明白,这是一条伪指令表示当前执行指令(0x70007770) + 0x320 = 0x70007a90
而不再是按照流水线理解。伪指令在经过汇编器汇编的过程中,会被分解成ADD或SUB指令的形式。
再看一条普通的带有PC指针偏移的LDR指令:
0x700082ec:    4a0f        .J      LDR      r2,[pc,#60] ; [0x7000832c] = 0x228e
这里pc是0x700082ec + 0x3C(#60) +0X4(三级指令流水线,thumb指令,每条指令2字节)= 0x7000832c
ARM指令手册也讲ADR指令时也有讲:http://www.keil.com/support/man/docs/armasmref/armasmref_Babcjaii.htm
ADR produces position-independent code, because the assembler generates an instruction that adds or subtracts a value to the PC.
另:网上一篇很好的讨论:http://stackoverflow.com/questions/3583606/need-help-to-understand-these-arm-instructions
另:推荐一篇博客:《ARM汇编中的ldr和adr的区别及其在uboot中相关源码的分析》http://blog.csdn.net/ce123_zhouwei/article/details/7277114

关于R0-R15寄存器的描述,除了看ARM架构手册(如ARMV7)也可参照AAPCS(Procedure Call Standard for the ARM® Architecture).

以上的程序是在keilMDK下编译的STM32F103工程。keilMDK默认编译是C89标准的(ARM编译器手册中讲的是C90标准或C95标准,关于C标准参照:http://www.cprogramdevelop.com/4149211/ 或附录)。如果但keilMDK声明是支持C99的,只需要在编译选项中增加--c99即可(参照ARM手册:using the compiler.pdf)


针对ARM体系结构的ABI请参照:http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.subset.swdev.abi/index.html







附录

C language specification: C89, C90, C95, C99

Tag: gcc, C + + / C, c, compiler, language Category: C Author: y1039569960 Date: 2013-01-22

This article is reproduced

[K & R C] 1978 years, Dennis Ritchie and Brian Kernighan co-launched "The C Programming Language" of the first edition (in accordance with established practice, the classics must have referred to, the writings referred to as K & R), a reference guide in the end of the book (Reference Manual ) one gives a complete definition of the C language, to become the de factostandard for the C language was known as K & R C. This year, the C language is ported to a variety of models, and are subject to a wide range of support, the C language in the software development almost dominate the world.

C89 (ANSI C) with the C language in many areas of promotion, application, some new featurescontinue to be a variety of compiler implemented and added. Thus, the establishment of a new "unambiguous, specific platform-independent C language definition become more and more important things. In 1983, ASC X3 (ANSI under responsible for information technologystandards of the institution, now renamed as INCITS) set up a dedicated Technical Committee J11 (J11 Commission, Stands for X3J11), responsible for drafting the draftstandard on the C language. 1989, the draft ANSI formally adopted the American NationalStandards, known as the C89 standard.

C90 (ISO C)? followed the "The C Programming Language" second edition was published, the book contents updated according to the ANSI C (C89). In 1990, the ISO / IEC JTC1/SC22/WG14 (ISO / IEC Joint Technical Commission I 22 Sub-Committee 14 Working Group) efforts, ISO approved ANSI C as an international standard. So the ISO C (also known as C90) was born. In addition to some of the details of the standard document printing arrangement ISO C (C90) and ANSI C (C89) is technically exactly the same.

[C95], ISO 1994, 1996 were published C90 errata document, correct some typographical errors, and in 1995 passed a C90 Technical Supplement C90 slight expansion after expansion ISO C is called C95.

[C99] 1999, ANSI and ISO passed the latest version of the C language standards and technical errata document, thestandard is known as C99. This is basically on the C language, the most authoritative definition.

, C compiler provides full support of C89 (C90) C99 provides only partial support, there are still some support for some K & R C style.

The C language specification C89 (c90), C95 (94) and c99. C89 is a the earliest C languagespecification, 89, 90, introduced first by the American National Standards Institute ANSI version, and later was accepted as ISO international standard (ISO / IEC 9899:1990), and thus sometimes known as C90. 94 and 96, respectively c90 two bug fixes, gcc support is a revised version of the c89 (90) C language specification. 90 Specification Version amendment in 1995, called C95 or AMD1. GCC also supports C95 specifications. The latest C specification (ISO / IEC 9899:1999), often called the C99 specification amendments enacted in 1999. C99 2001 C99error correction, gcc supports the revised specification, but so far, gcc also did not complete the full support of the C99 specification.

Attached: C language origin

       The first prototype of origin] C language is Algol 60 1963, Cambridge University developed it into a CPL (Combined Programing Language). In 1967, the University of Cambridge Matin Richards simplified CPL language BCPL language. In 1970, Ken Thompson of Bell Laboratories (Bell Labs) will BCPL modify, and named their B language means to extract the essence of the CPL (the Boiling CPL down to its basic good features). And wrote the first UNIX system B language. In 1973, AT & T Bell Labs, Dennis Ritchie (DMRitchie) on the basis of language BCPL and B to design a new language, take the second letter in the name of BCPL, which is the famous C language. Shortly thereafter, the UNIX kernel (Kernel) and applications entirely in C rewritten Since then, C language has become the most widely used UNIX environment mainstream programming languages.




0 0