Chinaunix首页 | 论坛 | 博客
  • 博客访问: 219991
  • 博文数量: 19
  • 博客积分: 757
  • 博客等级: 军士长
  • 技术积分: 320
  • 用 户 组: 普通用户
  • 注册时间: 2010-12-08 07:55
个人简介

醉卧沙场君莫笑

文章分类

全部博文(19)

文章存档

2016年(5)

2015年(2)

2014年(3)

2013年(1)

2012年(5)

2011年(3)

分类: LINUX

2014-01-21 21:49:55

    前面介绍了怎么自己动手编译工具链,但是只是动手编,不改点什么体现不出技术含量啊!
    
   现在我们想让gcc支持新的指令。先想想该怎么做。将指令编码转换成二进制的命令ar和二进制转换成指令编码的命令objdump都是binutils里面的工具。由此我们推断相关的代码肯定在binutils里面。所以我们查看下它的代码。我们知道mips里有一条dmtc0的指令比较特殊,所以搜索一下:


  1. binutils-2.21.1$ grep '\' -RIi *
    哦!出现了一大串,但是好多是testsuite里面的,猜测其是为了测试而用的。那么忽略他们:
  1. binutils-2.21.1$ grep '\' -RIi * | grep -v testsuite
  2.     opcodes/ChangeLog-0203: of mfc0, mtc0, dmfc0, and dmtc0 to print CP0+sel register
  3.     opcodes/ChangeLog-2008: membership of di, dmfc0, dmtc0, ei, mfc0 and mtc0. Add dmfc2 and
  4.     opcodes/mips-opc.c:{"dmtc0", "t,G", 0x40a00000, 0xffe007ff, COD|RD_t|WR_C0|WR_CC, 0, I3|IOCT },
  5.     opcodes/mips-opc.c:{"dmtc0", "t,+D", 0x40a00000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC, 0, I64|IOCT},
  6.     opcodes/mips-opc.c:{"dmtc0", "t,G,H", 0x40a00000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC, 0, I64|IOCT},
    嗯,这次看起来很正常。那么我们就去看看这个mips-opc.c文件吧! 五秒钟后...全部指令都在这里,看起来就是他了!这些指令都是下面结构体的一项:
 
  1. struct mips_opcode
  2. {
  3. /* The name of the instruction. */
  4. const char *name;
  5. /* A string describing the arguments for this instruction. */
  6. const char *args;
  7. /* The basic opcode for the instruction. When assembling, this
  8.   opcode is modified by the arguments to produce the actual opcode
  9.   that is used. If pinfo is INSN_MACRO, then this is 0. */
  10. unsigned long match;
  11. /* If pinfo is not INSN_MACRO, then this is a bit mask for the
  12.   relevant portions of the opcode when disassembling. If the
  13.   actual opcode anded with the match field equals the opcode field,
  14.   then we have found the correct instruction. If pinfo is
  15.   INSN_MACRO, then this field is the macro identifier. */
  16. unsigned long mask;
  17. /* For a macro, this is INSN_MACRO. Otherwise, it is a collection
  18.   of bits describing the instruction, notably any relevant hazard
  19.   information. */
  20. unsigned long pinfo;
  21. /* A collection of additional bits describing the instruction. */
  22. unsigned long pinfo2;
  23. /* A collection of bits describing the instruction sets of which this
  24.   instruction or macro is a member. */
  25. unsigned long membership;
  26. }

    这里注释写的很清楚,第一项是指令名字,第二项是参数,第三项和第四项,我来解释一下。一条指令可能有几位是可以变动的(这几个bit可能指示哪个寄存器)。但是有某些位的值是固定的。match & mask之后的就是固定的值。由这个值来标识这个二进制码是什么指令。其他的位为0或者为0,都还是这一条指令。
    pinfo和pinfo2看起来是精确地描述指令参数/类型等。membership看起来像描述这条指令属于哪个指令集里引进来的。我们知道mips汇编里是可以通过.set mips64或者.set mips64r2来让产生的汇编里只产生相关指令集兼容的指令。这个功能应该就是通过membership来实现的。
    大概了解了下,咱们就开始动手加一条指令试试看了。首先要确定我们的指令编码不会和已有的指令编码冲突。这个怎么办呢?
    现在写了一个简单的c语言程序来测试一下:

  1. #include <stdio.h>


  2. int x[] = {0x000000ff, 0xa, 0xb,0xc,0xd,0xa0000a,0xbccccd, 0xdead};


  3. int main()
  4. {


  5. return 0;
  6. }
  7.     test$ mips64el-unknown-linux-gnu-gcc test.c
  8.     test$ mips64el-unknown-linux-gnu-objdump -D -j.data a.out 

  9.     a.out: file format elf32-ntradlittlemips

  10.     Disassembly of section .data:


  11.     100107a0 <__data_start>:
  12.             ...

  13.    100107b0 <x>:
  14.    100107b0: 000000ff dsra32 zero,zero,0x3
  15.    100107b4: 0000000a 0xa
  16.    100107b8: 0000000b 0xb
  17.    100107bc: 0000000c syscall
  18.    100107c0: 0000000d break
  19.    100107c4: 00a0000a 0xa0000a
  20.    100107c8: 00bccccd break 0xbc,0x333
  21.    100107cc: 0000dead 0xdead

    哈哈,看起来运气不错,随便写了几个数字就有4个数字是不能被反汇编的。看起来dead这个很酷啊!好吧,就这么愉快地决定了。就用你做我们的新指令编码了。那么在
    const struct mips_opcode mips_builtin_opcodes[] =
    的正文里加入一行:
{"dead",    "",         0x0000dead, 0xffffffff, 0,                      INSN2_ALIAS,    I1      },
    为什么没有参数呢?没有参数容易啊。那么就开始编译吧。好的,接下来是一顿build...
    20分钟后...(在编的时候,作者忧郁地思考,能不能只编这一个而不编译全套工具链呢?)
    终于全编完了。于是我们兴奋地做一个测试:

点击(此处)折叠或打开

  1. #include <stdio.h>


  2. int main()
  3. {
  4. asm volatile ("dead;nop;dead;nop;nop;"::);


  5. return 0;
  6. }

    编译:
    test$ mips64el-unknown-linux-gnu-gcc 11.c
    完全没有问题地通过了。那么再看看反汇编(只看main函数):

点击(此处)折叠或打开

  1. 100005d0 <main>:
  2. 100005d0: 27bdfff0 addiu sp,sp,-16
  3. 100005d4: ffbe0008 sd s8,8(sp)
  4. 100005d8: 03a0f02d move s8,sp
  5. 100005dc: 0000dead dead
  6. 100005e0: 00000000 nop
  7. 100005e4: 0000dead dead
  8. ...
  9. 100005f0: 0000102d move v0,zero
  10. 100005f4: 03c0e82d move sp,s8
  11. 100005f8: dfbe0008 ld s8,8(sp)
  12. 100005fc: 03e00008 jr ra
  13. 10000600: 27bd0010 addiu sp,sp,16
    大功告成!

阅读(2373) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~