C Language
인라인 어셈블리
수색…
비고
인라인 어셈블리는 C 소스 코드의 중간에 어셈블리 명령어를 추가하는 관행입니다. ISO C 표준은 인라인 어셈블리를 지원할 필요가 없습니다. 필수가 아니므로 인라인 어셈블리 구문은 컴파일러마다 다릅니다. 일반적으로 지원되는 경우에도 인라인 어셈블리를 사용해야하는 이유는 거의 없으며 그렇지 않은 경우 많은 이유가 있습니다.
찬성
- 성능 연산에 대한 특정 어셈블리 명령어를 작성하면 컴파일러에서 생성 된 어셈블리 코드보다 우수한 성능을 얻을 수 있습니다. 이러한 성능 향상은 거의 없습니다. 대부분의 경우 옵티마이 저가 작업을 수행 할 수 있도록 C 코드를 재배치하여 성능을 향상시킬 수 있습니다.
- 하드웨어 인터페이스 장치 드라이버 또는 프로세서 시작 코드는 올바른 레지스터에 액세스하고 특정 작업이 특정 순서로 발생하고 작업간에 특정 지연이 발생하도록 보장하기 위해 일부 어셈블리 코드가 필요할 수 있습니다.
단점
- 컴파일러 이식성 인라인 어셈블리의 구문은 한 컴파일러에서 다른 컴파일러로 동일하지 않을 수 있습니다. 다른 컴파일러에서 지원해야하는 인라인 어셈블리가있는 코드를 작성하는 경우 선행 처리기 매크로 (
#ifdef
)를 사용하여 사용중인 컴파일러를 확인하십시오. 그런 다음 지원되는 각 컴파일러에 대해 별도의 인라인 어셈블리 섹션을 작성합니다. - 프로세서 이식성 x86 프로세서 용 인라인 어셈블리는 작성할 수 없으며 ARM 프로세서에서 작동 할 수 있습니다. 인라인 어셈블리는 특정 프로세서 또는 프로세서 제품군 용으로 작성되었습니다. 다른 프로세서에서 지원하려는 인라인 어셈블리가있는 경우 전 처리기 매크로를 사용하여 코드를 컴파일 할 프로세서를 확인하고 적절한 어셈블리 코드 섹션을 선택하십시오.
- 향후 성능 변경 인라인 어셈블리는 특정 프로세서 클럭 속도를 기반으로 지연을 예상하여 작성 될 수 있습니다. 프로그램이 더 빠른 시계로 프로세서 용으로 컴파일되면 어셈블리 코드가 예상대로 수행되지 않을 수 있습니다.
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));
최종 결과는 정확히 동일합니다.