Inline Specifier

From Embedded Systems Learning Academy
Revision as of 05:41, 11 January 2023 by 243 user3 (talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

inline is a specifier for a function in C/C++ that tells a compiler to replace a function call in assembly with the contents of that function definition. It is most often used when trying to speed up a program as it takes out the overhead of a function call. it is particularly useful with small functions that are called often. However, the specifier will also increase the size of your program as it takes away the benefit of re-usability at the assembly level.

Basic Example of the Inline Specifier

In the following example, there are two functions that do the same thing. Except one uses the inline specifier and the other does not. When compiled using compiler optimizations, the function with the inline specifier will not have a function call. Rather, the contents of the function will be put directly in the main function of the assembly output. Note: If compiled without any optimizations -O0, the inline specifier will be ignored.

#include "stdio.h"

void print_NON_inline()
{
	printf("%d", 2);
}

inline void print_WITH_inline()
{
	printf("%d", 3);
}

int main(void)
{
	print_NON_inline();
	print_WITH_inline(); 
	return 1;
}

The following was created by Linux g++ with an optimization of -O1.

00000000 <print_NON_inline()>:
_Z16print_NON_inlinev():
   0:	83 ec 10             	sub    $0x10,%esp
   3:	6a 02                	push   $0x2
   5:	68 00 00 00 00       	push   $0x0	6: R_386_32	.rodata.str1.1
   a:	6a 01                	push   $0x1
   c:	e8 fc ff ff ff       	call   d <print_NON_inline()+0xd>	d: R_386_PC32	__printf_chk
  11:	83 c4 1c             	add    $0x1c,%esp
  14:	c3                   	ret    

00000015 <main>:
main():
  15:	8d 4c 24 04          	lea    0x4(%esp),%ecx
  19:	83 e4 f0             	and    $0xfffffff0,%esp
  1c:	ff 71 fc             	pushl  -0x4(%ecx)
  1f:	55                   	push   %ebp
  20:	89 e5                	mov    %esp,%ebp
  22:	51                   	push   %ecx
  23:	83 ec 04             	sub    $0x4,%esp
  26:	e8 fc ff ff ff       	call   27 <main+0x12>	27: R_386_PC32	print_NON_inline()
  2b:	83 ec 04             	sub    $0x4,%esp
  2e:	6a 03                	push   $0x3
  30:	68 00 00 00 00       	push   $0x0	31: R_386_32	.rodata.str1.1
  35:	6a 01                	push   $0x1
  37:	e8 fc ff ff ff       	call   38 <main+0x23>	38: R_386_PC32	__printf_chk
  3c:	83 c4 10             	add    $0x10,%esp
  3f:	b8 01 00 00 00       	mov    $0x1,%eax
  44:	8b 4d fc             	mov    -0x4(%ebp),%ecx
  47:	c9                   	leave  
  48:	8d 61 fc             	lea    -0x4(%ecx),%esp
  4b:	c3                   	ret

Inline Specifier With a Recursive Function

For recursive functions, the inline specifier will attempt to take out as many recursive calls as possible but it cannot get rid of all of them. In the below example, there are two recursive factorial functions, one without the inline specifier and one with. The implementation without the inline specifier, the compiler simply creates a recursive assembly function call. The implementation with the inline specifier, the compiler optimizes to use as many registers as it can to more quickly run the factorial calculations. It computes five factorials using four registers and then if needed will call itself again. Note: This is only an example. Different compilers will optimize in different ways and the optimization will vary depending on how aggressive the optimization is. The following was created by Linux g++ with an optimization of -O1.

#include "stdio.h"

int factorial_WITHOUT(int a)
{
    if(a < 2){
        return 1;
    }
    else
    {
        return a * factorial_WITHOUT(a-1);  
    }
}

inline int factorial_WITH(int a)
{
    if(a < 2){
        return 1;
    }
    else
    {
        return a * factorial_WITH(a-1);
    }
}
int main(void)
{
    printf("%d\n", factorial_WITHOUT(7));
    printf("%d\n", factorial_WITH(7));
    return 1;
}
Disassembly of section .text:

00000000 <factorial_WITHOUT(int)>:
_Z17factorial_WITHOUTi():
   0:   53                      push   %ebx
   1:   83 ec 08                sub    $0x8,%esp
   4:   8b 5c 24 10             mov    0x10(%esp),%ebx
   8:   b8 01 00 00 00          mov    $0x1,%eax
   d:   83 fb 01                cmp    $0x1,%ebx
  10:   7e 12                   jle    24 <factorial_WITHOUT(int)+0x24>
  12:   83 ec 0c                sub    $0xc,%esp
  15:   8d 43 ff                lea    -0x1(%ebx),%eax
  18:   50                      push   %eax
  19:   e8 fc ff ff ff          call   1a <factorial_WITHOUT(int)+0x1a> 1a: R_386_PC32  factorial_WITHOUT(int)
  1e:   83 c4 10                add    $0x10,%esp
  21:   0f af c3                imul   %ebx,%eax
  24:   83 c4 08                add    $0x8,%esp
  27:   5b                      pop    %ebx
  28:   c3                      ret    

00000029 <main>:
main():
  29:   8d 4c 24 04             lea    0x4(%esp),%ecx
  2d:   83 e4 f0                and    $0xfffffff0,%esp
  30:   ff 71 fc                pushl  -0x4(%ecx)
  33:   55                      push   %ebp
  34:   89 e5                   mov    %esp,%ebp
  36:   51                      push   %ecx
  37:   83 ec 10                sub    $0x10,%esp
  3a:   6a 07                   push   $0x7
  3c:   e8 fc ff ff ff          call   3d <main+0x14>   3d: R_386_PC32  factorial_WITHOUT(int)
  41:   83 c4 0c                add    $0xc,%esp
  44:   50                      push   %eax
  45:   68 00 00 00 00          push   $0x0 46: R_386_32    .rodata.str1.1
  4a:   6a 01                   push   $0x1
  4c:   e8 fc ff ff ff          call   4d <main+0x24>   4d: R_386_PC32  __printf_chk
  51:   c7 04 24 05 00 00 00    movl   $0x5,(%esp)
  58:   e8 fc ff ff ff          call   59 <main+0x30>   59: R_386_PC32  factorial_WITH(int)
  5d:   83 c4 0c                add    $0xc,%esp
  60:   8d 04 40                lea    (%eax,%eax,2),%eax
  63:   6b c0 0e                imul   $0xe,%eax,%eax
  66:   50                      push   %eax
  67:   68 00 00 00 00          push   $0x0 68: R_386_32    .rodata.str1.1
  6c:   6a 01                   push   $0x1
  6e:   e8 fc ff ff ff          call   6f <main+0x46>   6f: R_386_PC32  __printf_chk
  73:   83 c4 10                add    $0x10,%esp
  76:   b8 01 00 00 00          mov    $0x1,%eax
  7b:   8b 4d fc                mov    -0x4(%ebp),%ecx
  7e:   c9                      leave  
  7f:   8d 61 fc                lea    -0x4(%ecx),%esp
  82:   c3                      ret    

Disassembly of section .text._Z14factorial_WITHi:

00000000 <factorial_WITH(int)>:
_Z14factorial_WITHi():
   0:   55                      push   %ebp
   1:   57                      push   %edi
   2:   56                      push   %esi
   3:   53                      push   %ebx
   4:   83 ec 1c                sub    $0x1c,%esp
   7:   8b 5c 24 30             mov    0x30(%esp),%ebx
   b:   b8 01 00 00 00          mov    $0x1,%eax
  10:   83 fb 01                cmp    $0x1,%ebx
  13:   7e 4b                   jle    60 <factorial_WITH(int)+0x60>
  15:   8d 73 ff                lea    -0x1(%ebx),%esi
  18:   83 fe 01                cmp    $0x1,%esi
  1b:   7e 40                   jle    5d <factorial_WITH(int)+0x5d>
  1d:   8d 7b fe                lea    -0x2(%ebx),%edi
  20:   83 ff 01                cmp    $0x1,%edi
  23:   7e 35                   jle    5a <factorial_WITH(int)+0x5a>
  25:   8d 6b fd                lea    -0x3(%ebx),%ebp
  28:   83 fd 01                cmp    $0x1,%ebp
  2b:   7e 2a                   jle    57 <factorial_WITH(int)+0x57>
  2d:   8d 43 fc                lea    -0x4(%ebx),%eax
  30:   89 c2                   mov    %eax,%edx
  32:   b8 01 00 00 00          mov    $0x1,%eax
  37:   89 54 24 0c             mov    %edx,0xc(%esp)
  3b:   83 fa 01                cmp    $0x1,%edx
  3e:   7e 14                   jle    54 <factorial_WITH(int)+0x54>
  40:   83 ec 0c                sub    $0xc,%esp
  43:   8d 43 fb                lea    -0x5(%ebx),%eax
  46:   50                      push   %eax
  47:   e8 fc ff ff ff          call   48 <factorial_WITH(int)+0x48>    48: R_386_PC32  factorial_WITH(int)
  4c:   83 c4 10                add    $0x10,%esp
  4f:   0f af 44 24 0c          imul   0xc(%esp),%eax
  54:   0f af c5                imul   %ebp,%eax
  57:   0f af c7                imul   %edi,%eax
  5a:   0f af c6                imul   %esi,%eax
  5d:   0f af c3                imul   %ebx,%eax
  60:   83 c4 1c                add    $0x1c,%esp
  63:   5b                      pop    %ebx
  64:   5e                      pop    %esi
  65:   5f                      pop    %edi
  66:   5d                      pop    %ebp
  67:   c3                      ret