130 likes | 418 Views
시스템 프로그래밍 실습. ASSEMBLY 1. 컴퓨터 언어의 3 단계 기계어 어셈블리어 고급언어 어셈블리어 인간이 이해 할 수 있는 문자열로 기계어와 1:1 대응관계를 이룸. INTRODUCE. 일반적인 어셈블리어 구성 라벨 (Label) 연상기호 (Mnemonic) 연산수 (Operand) 전형적인 구조 eax 레지스터에 숫자 10 저장. ASSEMBLY LANGUAGE. movl $10, $eax. 어셈블리와 C/C++ 을 함께 사용하는 방법
E N D
시스템 프로그래밍 실습 ASSEMBLY 1
컴퓨터 언어의 3단계 • 기계어 • 어셈블리어 • 고급언어 어셈블리어 • 인간이 이해 할 수 있는 문자열로 기계어와 1:1 대응관계를 이룸 INTRODUCE
일반적인 어셈블리어 구성 • 라벨 (Label) • 연상기호 (Mnemonic) • 연산수 (Operand) 전형적인 구조 • eax 레지스터에 숫자 10 저장 ASSEMBLY LANGUAGE movl $10, $eax
어셈블리와 C/C++을 함께 사용하는 방법 • 어셈블리 소스와 C/C++ 소스를 함께 컴파일 • 일반적으로 어셈블리 파일은 *.s 확장자를 가짐 • GCC에서는 어셈블리 컴파일을 지원함 • gcc c_source.c asm_source.s 로 컴파일 가능 • 어셈블리 오브젝트와 C/C++ 오브젝트를 함께 컴파일 • GCC로 각자의 *.o 파일을 만들어 함께 컴파일 • 인라인 어셈블리사용 • C 소스코드 내부에 직접 어셈블리어 코드를 입력 • 일반적인 어셈블리어와는 모양이 조금 다름 ASSEMBLY & C/C++
사용 목적 • C/C++ 로할 수 없는 작업 • 빠른 속도가 필요한 작업 • 레지스터 사용을 직접 제어하기 위한 작업 • 고급언어가 사용하지 못하는 프로세서 특정 명령 사용 • 장치주소 등의 접근을 위한 커널 코드 INLINE ASSEMBLY
인라인 어셈블리 구조 • 어셈블리 명령 (asms) • 출력 변수 (output) • 입력 변수 (input) • 값이 바뀌는 레지스터 (clobber) 문법 INLINE ASSEMBLY • __asm__ __volatile__ (asms : output : input : clobber);
설명 __asm__ • 다음에 나오는 것이 인라인 어셈블리어 임을 나타낸다. • Gcc에서는 asm 도 가능하지만 ANSI에 __asm__으로 정의되어 있다 __volatile__ • 최적화나 위치변화 등을 피하기 위해 사용된다. • 이것이 없을 경우 컴파일러 최적화 시 버그가 발생할 수 있다 INLINE ASSEMBLY
설명 • asms • 따옴표로 둘러싸인 어셈블리어 코드를 삽입 • 코드 내에서 %x와 같은 형태로 input, output 파라미터 사용 • output • “constraint” (variable)형태의 리스트 • input • output과 같음 • clobber • output, input에는 명시되지 않지만 asms를 실행해서 값이 변하는 것을 적음 INLINE ASSEMBLY
변형 문법 • asms는 반드시 있어야 하지만 output, input, clobber는 각각 생략할 수 있음 • \n\t 의 사용 • 어셈블리어로 확인할 때 줄을 맞추어 두는 것이 디버깅에 좋다 INLINE ASSEMBLY • __asm__ __volatile__ (asms : output); // input, clobber 생략 • __asm__ __volatile__ (asms : : input : clobber); // output 생략 • __asm__ __volatile__ (“movl %1 %0\n\taddl %2 %0” • : “=r” (out) • : “r” (x) “r” (y));
Constraints INLINE ASSEMBLY • 'm' 아키텍처가 지원하는 모든 종류의 메모리 어드레스를 사용하는 오퍼랜드 • 'o' 옵셋화 가능한 어드레스를 사용하는 메모리 오퍼랜드 • 'V' 옵셋화 불가능한 어드레스를 사용하는 메모리 오퍼랜드 • '<' 자동 감소(미리 감소하거나 나중에 감소한다) 어드레스용 메모리 오퍼랜드 • '>' 자동 증가(미리 증가하거나 나중에 증가한다) 어드레스용 메모리 오퍼랜드 • 'r' 일반 레지스터 사용 오퍼랜드 • 'd', 'a', 'f', ... 시스템에 따른 레지스터를 나타내는 다른 오퍼랜드로 d, a, f는 각각 68000/68020에서 데이터, 어드레스,플로팅 포인트 레지스터를 나타낸다. • 'i' immediate 정수 값을 나타내는 오퍼랜드. 심볼로 된 상수도 여기에 해당한다. • 'n' immediate 정수 값으로 알려진 정수 값을 나타낸다. 많은 시스템이 어셈블 할 때 한 워드 이하의 오퍼랜드용 상수를지원하지 않으므로 'i'보단 'n'을 사용하는 것이 바람직하다. • 'I', 'J', 'K', ... 'P' 시스템에 따라 특정 범위 내의 값을 나타내는 오퍼랜드. 68000에선 'I'가 1에서 8까지의 값을 나타낸다.이것은 시프트 명령에서 허용된 시프트 카운트의 범위다. • 'E' immediate 플로팅 오퍼랜드로 호스트와 같은 타겟 플로팅 포인트 포맷인 경우에만 사용 가능. • 'F' immediate 플로팅 오퍼랜드. • 'G', 'H' 특정 범위 내의 값을 나타내는 플로팅 오퍼랜드로 시스템에 따라 다르다. • 's' 값이 명확히 정해지지 않은 immediate 정수를 나타내는 오퍼랜드 • 's' 값이 명확히 정해지지 않은 immediate 정수를 나타내는 오퍼랜드. 's'를 'i'? 대신 쓰는 이유는 좀더 좋은 코드를 만들어낼 수도 있기 때문이다. • 'g' 특수 레지스터를 제외한 일반 레지스터, 메모리 혹은 immediate 정수 중 아무것이나 나타내는 오퍼랜드. • '0', '1', '2', ... '9' 같이 사용된 오퍼랜드의 번호를 나타냄. • 'p' 올바른 메모리 어드레스를 나타내는 오퍼랜드. "load address"와 "push address" 명령을 위한 것. • 'Q', 'R', 'S', ... 'U' Q에서 U까지의 문자는 시스템에 따라 변하는 여러 다른 오퍼랜드를 의미한다.
Modifier INLINE ASSEMBLY • '=' • 오퍼랜드가 쓰기 전용임을 나타냄. 이전 값은 없어지고 새로운 값으로 교체됨. • '+' • 읽기, 쓰기 모두 가능. '='는 보통 output용 '+'는 input/output 모두에 사용 가능하다. 나머지 다른 모든 오퍼랜드는 input 전용으로 간주된다. • '&‘ • "earlyclobber" 오퍼랜드를 나타내고 input 오퍼랜드를 사용하는 명령이 끝나기 전에 변경 된다는 것을 의미한다.그래서 input 오퍼랜드나 메모리 어드레스의 일부를 나타내는 레지스터엔 못 쓴다. • gcc는 input 변수가 다 사용되고 나면 output에 사용된다고 가정하기 때문에 input에 사용된 변수가 output과 같게 되고 또 output이 input 보다 먼저 사용되는 경우가 발생할 수 있다. 이런 경우를 막기 위해 output에 사용된 변수가 input이 모두 사용되기 전에 변경될 수도 있다고 알려줘야만 input과 output이 같아져 생기는 에러를 막을 수 있다. • '%' %뒤에 따라오는 오퍼랜드로 대체 가능함을 나타낸다. 직접 레지스터를 명시하고 사용할 때 %%eax 등과 같이 사용 • '#' # 이후의 쉼표가 나올 때 까지 모든 문자를 constraints로 취급하지 않는다.
EXAMPLE 1 .globl main main: movl $10, %eax imull %eax, %eax ret
EXAMPLE 2 #include <stdio.h> #include <stdlib.h> int main() { int a, sum; a = 1; __asm__ __volatile__( "movl %1, %0 \n\t" "addl %2, %0 \n\t" "addl %3, %0 \n\t" "addl %4, %0 \n\t" "addl %5, %0 " : “=g” (sum) : “r” (a), “r” (a+1), “r” (a+2), “r” (a+3), “r” (a+4) ); printf("a=%d, sum=%d\n", a, sum); return 0; }