수색…


비고

인라인 어셈블리는 C 소스 코드의 중간에 어셈블리 명령어를 추가하는 관행입니다. ISO C 표준은 인라인 어셈블리를 지원할 필요가 없습니다. 필수가 아니므로 인라인 어셈블리 구문은 컴파일러마다 다릅니다. 일반적으로 지원되는 경우에도 인라인 어셈블리를 사용해야하는 이유는 거의 없으며 그렇지 않은 경우 많은 이유가 있습니다.

찬성

  1. 성능 연산에 대한 특정 어셈블리 명령어를 작성하면 컴파일러에서 생성 된 어셈블리 코드보다 우수한 성능을 얻을 수 있습니다. 이러한 성능 향상은 거의 없습니다. 대부분의 경우 옵티마이 저가 작업을 수행 할 수 있도록 C 코드를 재배치하여 성능을 향상시킬 수 있습니다.
  2. 하드웨어 인터페이스 장치 드라이버 또는 프로세서 시작 코드는 올바른 레지스터에 액세스하고 특정 작업이 특정 순서로 발생하고 작업간에 특정 지연이 발생하도록 보장하기 위해 일부 어셈블리 코드가 필요할 수 있습니다.

단점

  1. 컴파일러 이식성 인라인 어셈블리의 구문은 한 컴파일러에서 다른 컴파일러로 동일하지 않을 수 있습니다. 다른 컴파일러에서 지원해야하는 인라인 어셈블리가있는 코드를 작성하는 경우 선행 처리기 매크로 ( #ifdef )를 사용하여 사용중인 컴파일러를 확인하십시오. 그런 다음 지원되는 각 컴파일러에 대해 별도의 인라인 어셈블리 섹션을 작성합니다.
  2. 프로세서 이식성 x86 프로세서 용 인라인 어셈블리는 작성할 수 없으며 ARM 프로세서에서 작동 할 수 있습니다. 인라인 어셈블리는 특정 프로세서 또는 프로세서 제품군 용으로 작성되었습니다. 다른 프로세서에서 지원하려는 인라인 어셈블리가있는 경우 전 처리기 매크로를 사용하여 코드를 컴파일 할 프로세서를 확인하고 적절한 어셈블리 코드 섹션을 선택하십시오.
  3. 향후 성능 변경 인라인 어셈블리는 특정 프로세서 클럭 속도를 기반으로 지연을 예상하여 작성 될 수 있습니다. 프로그램이 더 빠른 시계로 프로세서 용으로 컴파일되면 어셈블리 코드가 예상대로 수행되지 않을 수 있습니다.

gcc 기본 asm 지원

gcc를 사용한 기본 어셈블리 지원의 구문은 다음과 같습니다.

asm [ volatile ] ( AssemblerInstructions )

여기서 AssemblerInstructions 는 지정된 프로세서의 직접 어셈블리 코드입니다. volatile 키워드는 선택 사항이며 기본 asm 문 내에서 gcc가 코드를 최적화하지 않으므로 아무 효과가 없습니다. AssemblerInstructions 에는 여러 어셈블리 명령어가 포함될 수 있습니다. asm 루틴이 C 함수 외부에 존재해야하는 경우 기본 asm 문이 사용됩니다. 다음 예제는 GCC 매뉴얼에서 가져온 것입니다.

 /* Note that this code will not compile with -masm=intel */
 #define DebugBreak() asm("int $3")

이 예제에서는 코드의 다른 위치에서 DebugBreak() 를 사용할 수 있으며 int $3 어셈블리 명령을 실행합니다. gcc가 기본 asm 문에서 코드를 수정하지 않더라도 옵티마이 저는 여전히 연속적인 asm 문을 이동할 수 있습니다. 특정 순서로 발생해야하는 여러 어셈블리 명령어가있는 경우 하나의 asm 문에 포함하십시오.

gcc 확장 된 asm 지원

gcc의 확장 된 asm 지원은 다음 구문을 사용합니다.

asm [volatile] ( AssemblerTemplate
                  : OutputOperands
                  [ : InputOperands
                  [ : Clobbers ] ])
 
 asm [volatile] goto ( AssemblerTemplate
                       :
                       : InputOperands
                       : Clobbers
                       : GotoLabels)

여기서 AssemblerTemplate 어셈블러 명령어에 대한 템플릿이다 OutputOperands 어셈블리 코드에 의해 수정 될 수있는 C 변수이다 InputOperands 입력 매개 변수로서 사용되는 C 변수이다 Clobbers 목록 또는 어셈블리 코드에 의해 수정되는 레지스터되고 GotoLabels 어셈블리 코드에서 사용할 수있는 goto 문 레이블입니다.

확장 형식은 C 함수 내에서 사용되며 인라인 어셈블리의보다 일반적인 사용법입니다. 다음은 ARM 프로세서의 16 비트 및 32 비트 숫자를 바이트 스왑하는 Linux 커널의 예입니다.

/* From arch/arm/include/asm/swab.h in Linux kernel version 4.6.4 */
#if __LINUX_ARM_ARCH__ >= 6

static inline __attribute_const__ __u32 __arch_swahb32(__u32 x)
{
    __asm__ ("rev16 %0, %1" : "=r" (x) : "r" (x));
    return x;
}
#define __arch_swahb32 __arch_swahb32
#define __arch_swab16(x) ((__u16)__arch_swahb32(x))

static inline __attribute_const__ __u32 __arch_swab32(__u32 x)
{
    __asm__ ("rev %0, %1" : "=r" (x) : "r" (x));
    return x;
}
#define __arch_swab32 __arch_swab32

#endif

각 asm 섹션은 변수 x 를 입력 및 출력 매개 변수로 사용합니다. C 함수는 조작 된 결과를 리턴합니다.

확장 된 asm 형식을 사용하면 gcc는 C 코드를 최적화하는 데 사용하는 것과 동일한 규칙에 따라 asm 블록에서 어셈블리 명령어를 최적화 할 수 있습니다. asm 섹션을 변경하지 않으려면 asm 섹션에 volatile 키워드를 사용하십시오.

gcc 매크로의 인라인 어셈블리

어셈블리 명령어를 매크로 안에 넣고 함수를 호출하는 것처럼 매크로를 사용할 수 있습니다.

#define mov(x,y) \
{ \
    __asm__ ("l.cmov %0,%1,%2" : "=r" (x) : "r" (y), "r" (0x0000000F)); \
}

/// some definition and assignment
unsigned char sbox[size][size];
unsigned char sbox[size][size];

///Using
mov(state[0][1], sbox[si][sj]);

C 코드에 포함 된 인라인 어셈블리 명령어를 사용하면 프로그램의 런타임을 향상시킬 수 있습니다. 이는 AES와 같은 암호화 알고리즘과 같이 시간이 중요한 상황에서 매우 유용합니다. 예를 들어, AES 알고리즘에서 필요한 간단한 시프트 연산의 경우, C 시프트 연산자 >> 로 직접 Rotate Right 어셈블리 명령어를 대체 할 수 있습니다.

'AES256'의 구현에서 'AddRoundKey ()'함수에 다음과 같은 문이 있습니다.

unsigned int w;          // 32-bit
unsigned char subkey[4]; // 8-bit, 4*8 = 32 

subkey[0] = w >> 24;     // hold 8 bit, MSB, leftmost group of 8-bits 
subkey[1] = w >> 16;     // hold 8 bit, second group of 8-bit from left    
subkey[2] = w >> 8;      // hold 8 bit, second group of 8-bit from right
subkey[3] = w;           // hold 8 bit, LSB, rightmost group of 8-bits

/// subkey <- w

그들은 단순히 subkey 배열에 w 의 비트 값을 할당합니다.

하나의 어셈블리 Rotate Right 연산을 사용하여 세 개의 shift + assign 및 assign C 표현식을 변경할 수 있습니다.

__asm__ ("l.ror  %0,%1,%2" : "=r" (* (unsigned int *) subkey)  : "r" (w), "r" (0x10));

최종 결과는 정확히 동일합니다.



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow