menu

在Linux内核中时常见到内嵌汇编语言的函数

1. 内联汇编做了什么

在Linux内核中,我们时常见到内嵌汇编语言的函数,向这种在C语言函数内部嵌入汇编代码的做法我们称之为内联汇编。尽管现在的编译器对程序的优化都很优秀了,但在某些对效率要求较高的场合仍需要手动优化,我们暂时先不关心具体的内联汇编的规则,先来看看内联汇编是如何提高效率的。

1.1. 优化对比测试

测试环境:imx6ull 编译器:arm-linux-gnueabihf-gcc 反汇编:arm-linux-gnueabihf-objdump Makefile:

test: main.c
        arm-linux-gnueabihf-gcc -o $@ $^

        arm-linux-gnueabihf-objdump -D test > test.dis
clean:
        rm test *.dis

1.1.1. 非内联汇编

写测试函数如下: main.c:

#include <stdio.h>
#include <stdlib.h>

int add(int a, int b)
{
	return a + b;
}

int main(int argc, char **argv)
{
	int a;
	int b;
	char *endptr;

	if (argc != 3)
	{
		printf("Usage: %s <val1> <val2>\n", argv[0]);
		return -1;
	}

	a = (int)strtol(argv[1], NULL, 0);
	b = (int)strtol(argv[2], NULL, 0);

	printf("%d + %d = %d\n", a, b, add(a, b));	
}

查看反汇编: 这是我们写的add函数:

00010404 <add>:
   10404:       b480            push    {r7}
   10406:       b083            sub     sp, #12
   10408:       af00            add     r7, sp, #0
   1040a:       6078            str     r0, [r7, #4]
   1040c:       6039            str     r1, [r7, #0]
   1040e:       687a            ldr     r2, [r7, #4]
   10410:       683b            ldr     r3, [r7, #0]
   10412:       4413            add     r3, r2
   10414:       4618            mov     r0, r3
   10416:       370c            adds    r7, #12
   10418:       46bd            mov     sp, r7
   1041a:       f85d 7b04       ldr.w   r7, [sp], #4
   1041e:       4770            bx      lr

然后在main函数中被调用:

00010420 <main>:
#...省略
10470:       f7ff ffc8       bl      10404 <add>
#...省略

1.1.2. 内联汇编

写测试函数如下: main.c:

#include <stdio.h>
#include <stdlib.h>

int add(int a, int b)
{
	int sum;
	__asm__ volatile (
		"add %0, %1, %2"
		:"=r"(sum)
		:"r"(a), "r"(b)
		:"cc"
	);
	return sum;
}

int main(int argc, char **argv)
{
	int a;
	int b;
	
	if (argc != 3)
	{
		printf("Usage: %s <val1> <val2>\n", argv[0]);
		return -1;
	}

	a = (int)strtol(argv[1], NULL, 0);	
	b = (int)strtol(argv[2], NULL, 0);	

	printf("%d + %d = %d\n", a, b, add(a, b));
	return 0;
}

00010474 <add>:
   10474:       1840            adds    r0, r0, r1
   10476:       4770            bx      lr

然后在main函数中被调用:

00010404 <main>:
#...省略
 10454:       f000 f80e       bl      10474 <add>
#...省略

1.2. 结论

可见,实现相同的功能,内联汇编add函数的指令相比纯C语言写的add函数大大简化,效率自然大大提高。

2. 语法规则

2.1. 内联汇编规则

asm [Qualifiers] (
                  ``AssemblerTemplate``
                  : ``OutputOperands``
                  : ``InputOperands``
                  : ``Clobbers`` 
                )

asm [Qualifiers] goto (
                      ``AssemblerTemplate``
                      : /* No outputs. */
                      : ``InputOperands``
                      : ``Clobbers``
                      : ``GotoLabels``
                    )

2.2. 示例

#include <stdio.h>
#include <stdlib.h>

int test(int a, int b)
{
	__asm__ goto (

		"cmp %1, %0\n\t"
    /* BLE指令:b比a小则跳转 */
		"blt %l2"
		: /* No outputs. */
		: "r"(a), "r"(b)
		: "cc"
		: carry);

	return 0;

carry:
	return 1;
}

int main(int argc, char **argv)
{
	int a;
	int b;

	if (argc != 3)
	{
		printf("Usage: %s <val1> <val2>\n", argv[0]);
		return -1;
	}

	a = (int)strtol(argv[1], NULL, 0);
	b = (int)strtol(argv[2], NULL, 0);

	printf("test return is %d\n",test(a, b));
	return 0;
}

2.3. imx6ull测试结果

BLE指令实现功能:b比a小则跳转

./test  1 2
test return is 0

./test  3 2
test return is 1

./test  2 2
test return is 0


更多文章 请访问havte官网

havte官网

关注微博 微信公众号

随时随地 想看就看

微信搜索公众号: havte
wechat 微信公众号:havte
微博搜索: havte官方微博
微博账号:havte官方微博