gcc оптимизирует обработку вызовов статических функций.

Недавно я обнаружил проблему сбоя. Дизассемблирование просматривало стек вызовов слой за слоем. После достижения определенной функции я не мог найти соответствующую строку кода. Затем я ввел определенную функцию, которую она вызывала, а затем связал последовательность вызовов. . Поэтому я провел небольшой эксперимент, чтобы посмотреть, как компилятор справится с этим на уровне сборки.

Код С:

#include <stdio.h>

static void myfunc(void)
{
	printf("myfunc in\n");
	printf("myfunc out\n");
}

int main(int argc, char *argv[])
{
	printf("main in\n");
	myfunc();
	printf("main out\n");
	return 0;
}

 

Скомпилируйте с помощью Arm-none-linux-gnueabi-gcc main.c, а затем используйте Arm-none-linux-gnueabi-objdump -d a.out, чтобы дизассемблировать выходные данные. Из фрагмента сборки ниже вы можете увидеть вызов основной функции. в myfunc:  bl 842c <myfunc>

0000842c <myfunc>:
    842c:	e92d4800 	push	{fp, lr}
    8430:	e28db004 	add	fp, sp, #4
    8434:	e59f000c 	ldr	r0, [pc, #12]	; 8448 <myfunc+0x1c>
    8438:	ebffffcd 	bl	8374 <_init+0x44>
    843c:	e59f0008 	ldr	r0, [pc, #8]	; 844c <myfunc+0x20>
    8440:	ebffffcb 	bl	8374 <_init+0x44>
    8444:	e8bd8800 	pop	{fp, pc}
    8448:	0000856c 	.word	0x0000856c
    844c:	00008578 	.word	0x00008578

00008450 <main>:
    8450:	e92d4800 	push	{fp, lr}
    8454:	e28db004 	add	fp, sp, #4
    8458:	e24dd008 	sub	sp, sp, #8
    845c:	e50b0008 	str	r0, [fp, #-8]
    8460:	e50b100c 	str	r1, [fp, #-12]
    8464:	e59f001c 	ldr	r0, [pc, #28]	; 8488 <main+0x38>
    8468:	ebffffc1 	bl	8374 <_init+0x44>
    846c:	ebffffee 	bl	842c <myfunc>
    8470:	e59f0014 	ldr	r0, [pc, #20]	; 848c <main+0x3c>
    8474:	ebffffbe 	bl	8374 <_init+0x44>
    8478:	e3a03000 	mov	r3, #0
    847c:	e1a00003 	mov	r0, r3
    8480:	e24bd004 	sub	sp, fp, #4
    8484:	e8bd8800 	pop	{fp, pc}
    8488:	00008584 	.word	0x00008584
    848c:	0000858c 	.word	0x0000858c

 

Затем используйте Arm-none-linux-gnueabi-gcc -O1 main.c, чтобы выполнить оптимизационную компиляцию уровня 1, и используйте Arm-none-linux-gnueabi-objdump -d a.out, чтобы дизассемблировать выходные данные. Myfunc не может быть найден в Сборка. В основной функции к ней нет вызова. На самом деле, myfunc меньше, и myfunc встроен в основную функцию. 8438-8444 — это два вызова printf в myfunc.

0000842c <main>:
    842c:    e92d4008     push    {r3, lr}
    8430:    e59f0020     ldr    r0, [pc, #32]    ; 8458 <main+0x2c>
    8434:    ebffffce     bl    8374 <_init+0x44>
    8438:    e59f001c     ldr    r0, [pc, #28]    ; 845c <main+0x30>
    843c:    ebffffcc     bl    8374 <_init+0x44>
    8440:    e59f0018     ldr    r0, [pc, #24]    ; 8460 <main+0x34>
    8444:    ebffffca     bl    8374 <_init+0x44>
    8448:    e59f0014     ldr    r0, [pc, #20]    ; 8464 <main+0x38>
    844c:    ebffffc8     bl    8374 <_init+0x44>
    8450:    e3a00000     mov    r0, #0
    8454:    e8bd8008     pop    {r3, pc}
    8458:    00008544     .word    0x00008544
    845c:    0000854c     .word    0x0000854c
    8460:    00008558     .word    0x00008558
    8464:    00008564     .word    0x00008564

 

---------------------------------------

    8438: e59f001c ldr r0, [pc, #28]; 845c <main+0x30>
    843c: ebffffcc bl 8374 <_init+0x44>
pc, #28 — это 845c, где хранится адрес памяти 854c, который будет (указатель памяти ) Данные, на которые указывает 854c, извлекаются и помещаются в r0, который является первым адресом памяти «myfunc in\n», а затем вызывается функция printf. Согласно соглашению о вызове функций, первым параметром является r0, за ним следуют r1 и r2, а все остальные параметры следует помещать в стек.

printf — это функция динамической библиотеки C. Здесь нет такого оператора, как bl printf. На самом деле это bl 8374 <_init+0x44>, а затем происходит переход к реальной функции печати. 

Guess you like

Origin blog.csdn.net/konga/article/details/117875310