Skip to content

Inline assembler

Intro

Inline assembly에서 정해주어야 하는 것들은 다음와 같다.

  • assembly 코드
  • output 변수들
  • input 변수들
  • output외에 값이 바뀌는 레지스터들
__asm__ __volatile__ (asms : output : input : clobber);
__asm__
인라인 어셈블리 키워드.
이 키워드는 asm으로도 쓸 수 있지만 ansi옵션으로 컴파일하게 되면 asm은 정의되어있지 않기 때문에 __asm__으로 쓰는 것이 좋다.
__volatile__
이 키워드는 해당하는 inline assembly를 optimization으로 제거하거나 변경하지 않게 고정한다.
GCC manual에 따르면 side effect가 없다고 여겨지는 경우 assembly를 없애거나 loop의 밖으로 빼는 optimization을 할 수 있다고 한다.
예를 들어 output이 있지만 실제로 output으로 쓰인 변수가 그 이후로 한 번도 쓰이지 않았다면 그 inline assembly는 프로그램의 수행에 아무런 영향을 끼치지 않는다고 생각하고 없애버리는 것입니다. 물론 조건을 정확하게 정해주면 굳이 __volaitile__을 붙이지 않더라도 제대로 작동하겠지만 가끔씩 엉뚱하게 되버리는 경우도 있기때문에 잘 생각해서 inline assembly를 쓰고 __volatile__을 붙여주는 것이 좋다.
asms
쌍따옴표로 둘러싸인 assembly 문자열. 문자열안에서 %n 형태로 input, output 인자들을 사용할 수 있으며 인자들이 치환된 후 그대로 컴파일 된 assembly에 나타난다.
output
쉼표로 구분된 "constraint"(variable)들의 리스트이며 각각이 inline assembly에서 쓰이는 output 인자를 나타낸다.
input
output과 같은 형태이며 input인자들을 나타낸다.
clobber
쉼표로 구분되는 쌍따옴표로 둘러싸인 레지스터 이름들의 리스트이며 input, output에 나오진 않았지만 해당 assembly를 수행한 결과로 값이 바뀌는 레지스터들을 나타낸다.

참고로 ouput, input, clobber는 비어있다면 뒤에서 부터 생략될 수 있다. 하지만 앞에 오는 파라미터가 비어있을 때는 :로 표시해야 한다.

Example

실제로 input, output이 쓰인 예는 아래와 같다.

int test_and_set_bit(int nr, volatile unsigned * addr)
{
    int oldbit;

    __asm__ __volatile__(
        "lock; btsl %2,%1\n\tsbbl %0,%0"
        :"=r" (oldbit),"=m" (*addr)
        :"r" (nr));
        return oldbit;
}

Simple example

불필요한 코드를 모두 제거한 아래와 같은 코드가 있다고 하자.

int main()
{
    int a = 11;
    return 0;
}

objdump1를 사용하여 asm 코드를 아래와 같이 확인할 수 있다.

_main:
       0:   55  pushq   %rbp
       1:   48 89 e5    movq    %rsp, %rbp
       4:   31 c0   xorl    %eax, %eax
       6:   c7 45 fc 00 00 00 00    movl    $0, -4(%rbp)
       d:   c7 45 f8 0b 00 00 00    movl    $11, -8(%rbp)
      14:   5d  popq    %rbp
      15:   c3  retq

d번째 라인을 보면 rbp에 11을 삽입하는 코드를 확인할 수 있다.

a값을 20으로 수정하는 inline asm코드는 아래와 같이 적용할 수 있다.

#include <stdio.h>
int main()
{
    int a = 11;
    __asm__ __volatile__ ("movl $20, -8(%rbp)");
    printf("%d", a);
    return 0;
}

실행하면 20이 출력되는 것을 확인할 수 있다.

See also

Favorite site

References


  1. objdump -d main.o 

  2. KLDPWiki-Docbook_Sgml_GCC_Inline_Assembly-KLDP.pdf 

  3. Introduction_to_x64_Assembly_-_kor.pdf