switch语句和汇编代码表示

  • Post author:
  • Post category:其他


statement(switch语句)可根据一个整数索引值(integer index)进行多重分支,处理有多种可能结果的测试时,这种语句特别有用。当开关情况数量比较多(如4个以上),并且值得范围跨度比较小时,GCC编译switch语句时会使用跳转表(jump table)这种数据结构;当不满足以上情况时编译方式和编译多个if-else语句的方式一样。这两种方式相比,跳转表的优点是执行开关语句的时间与开关情况的数量无关。

下面是引用GCC文档中的一段文字,具体解释了jump table的用法:

You can get the address of a label defined in the current function (or a containing function) with the unary(一元的) operator ‘&&’. The value has type void *. This value is a constant(常量) and can be used wherever a constant of that type is valid. For example: 
			 1. void *ptr; 
			 2. /* ... */ 
			 3. ptr = &&foo; 
 To use these values, you need to be able to jump to one. This is done with the computed goto statement1, goto *exp;. For example,
			 1. goto *ptr; 
Any expression of type void * is allowed. One way of using these constants is in initializing a staticarray that serves as a jump table: 
			 1. static void *array[] = { &&foo, &&bar, &&hack }; 
 Then you can select a label with indexing, like this:
			 1. goto *array[i];
 Note that this does not check whether the subscript(下标,脚注) is in bounds(限制范围)—array indexing in C never does that.(在C标	准中使用越界下标的结果是未定义的)
 Such an array of label values serves a purpose much like that of the switch statement. The switch statement is cleaner, so use that rather than an array unless the problem does not fit a switch statement very well.  
Another use of label values is in an interpreter(翻译程序) for threaded code(线程代码). The labels within the interpreter function can be stored in the threaded code for super-fast dispatching(调度).  
You may not use this mechanism to jump to code in a different function. If you do that, totally unpredictable things happen. The best way to avoid this is to store the label address only in automatic variables and never pass it as an argument.
 An alternate way to write the above example is 
			 1.static const int array[] = { &&foo - &&foo, &&bar - &&foo,&&hack - &&foo }; 				2.goto *(&&foo + array[i]); 
This is more friendly to code living in shared libraries, as it reduces the number of dynamic relocations that are needed, and by consequence, allows the data to be read-only. This alternative with label differences is not supported for the AVR target, please use the first approach for AVR programs. The &&foo expressions for the same label might have different values if the containing function is inlined or cloned. If a program relies on them being always the same, attribute((noinline,noclone)) should be used to prevent inlining and cloning. If &&foo is used in a static variable initializer, inlining and cloning is forbidden.

下面解释标签的作用:

1.jmp .Label

2. /* …

/

3. .Label:

/

… */

我的理解是Label的就等于与它所对应指令的地址,类似数组名,jmp 操作数实际上就是一个代码所在位置的地址。在jmp间接跳转:jmp

(%rdi,%rsi,1)中,

更像是c语言中的间接引用。

下面是一个跳转表:

.section .rodata

.align 8 //Align address to multipe of 8

.L4: //.L4是以下这个段的起始地址(更像一个指针的指针)

.quad .L3 //一下这个段或者说是一段内存,分为4个8字(64位),每一个8字内存中

.quad .L8 //存储着对应标签的值,也就是标签所对应指令的地址。(更像一个指针)

.quad .L5

.quad .L6引用文本



版权声明:本文为hui_chen123原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。