문제

나는 새로운 언어를 배우면서 얻는 가장 중요한 것 중 하나는 새로운 언어를 사용하는 방법이 아니라 그로부터 얻는 개념에 대한 지식이라는 생각을 굳게 믿는다. 나는 당신이 어셈블리가 얼마나 중요하거나 유용하다고 생각하는지 묻지 않으며, 실제 프로젝트에서는 결코 사용하지 않는지 신경 쓰지 않습니다.

내가 알고 싶은 것은 일반 프로그래머가 알아야 할 어셈블리의 개념이 가장 중요하다고 생각하는 것은 무엇입니까? 조립과 직접 관련이있을 필요는 없습니다. 또한 CPU 캐시와 같이 고급 언어로 모든 시간을 보내는 전형적인 프로그래머가 이해하지 못하거나 당연한 것으로 생각할 수도 있습니다.

도움이 되었습니까?

해결책

조립 언어는 몇 가지 큰 개념뿐만 아니라 많은 작은 것들을 가르쳐 줄 수 있다고 생각합니다.

여기서 생각할 수있는 몇 가지 사항을 나열하지만 X86과 RISC 명령 세트를 사용하고 배우고 사용하는 대체물은 없습니다.

당신은 아마도 정수 작업이 가장 빠르다고 생각할 것입니다. 정수의 정수 제곱근을 찾으려면 (예 : 바닥 (SQRT (i))를 찾으려면 정수 전용 근사치 루틴을 사용하는 것이 가장 좋습니다.

아아. 수학 공동 프로세서 (x86)는 fsqrt 지침. 플로트로 변환, 제곱근을 취하고 INT로 다시 변환하는 것이 모든 인기 알고리즘보다 빠릅니다.

그런 다음 어셈블리를 탐구 할 때까지 따라갈 수있는 메모리에 액세스 할 수 있지만 제대로 인식하지 못하는 것들이 있습니다. 링크 된 목록이 있고 목록의 첫 번째 요소에는 자주 액세스 해야하는 변수가 포함되어 있습니다. 목록은 거의 재정렬되지 않습니다. 글쎄, 해당 변수에 액세스해야 할 때마다 목록의 첫 번째 요소에 포인터를로드 한 다음이를 사용하고 변수를로드해야합니다 (사용 사이의 레지스터에 변수의 주소를 유지할 수 없다고 가정). . 대신 목록 외부에 변수를 저장 한 경우 단일로드 작업 만 필요합니다.

물론 여기에 몇 번의주기를 절약하면 요즘에는 일반적으로 중요하지 않습니다. 그러나 빠르게 필요한 코드를 작성하려는 경우, 이런 종류의 지식은 인라인 어셈블리와 일반적으로 다른 언어로 적용될 수 있습니다.

컨벤션에 전화하는 것은 어떻습니까? (일부 어셈블러는 당신을 위해 이것을 처리합니다 - 실제 프로그래머는 그것을 사용하지 않습니다.) 발신자 나 Callee가 스택을 정리합니까? 스택도 사용합니까? 레지스터에서 값을 전달할 수 있지만 재미있는 X86 명령 세트로 인해 특정 레지스터에서 특정 물건을 전달하는 것이 좋습니다. 그리고 어떤 레지스터가 보존됩니까? C 컴파일러가 실제로 최적화 할 수없는 것은 전화입니다.

리턴 주소를 밀고 절차에 jmping과 같은 요령은 거의 없습니다. 절차가 반환되면 푸시 된 주소로 이동합니다. 기능 호출에 대한 일반적인 사고 방식에서 벗어나는 것은 "깨달음 상태"중 하나입니다. 혁신적인 기능으로 프로그래밍 언어를 설계하려면 하드웨어가 할 수있는 재미있는 것들에 대해 알아야합니다.

어셈블리 언어에 대한 지식은 컴퓨터 보안에 대한 아키텍처 관련 사항을 가르칩니다. 버퍼 오버 플로우를 이용하거나 커널 모드로 나누는 방법과 이러한 공격을 방지하는 방법.

그런 다음 자체 수정 코드의 ubercoolness와 관련 문제로 재배치 및 코드에 패치 적용과 같은 메커니즘이 있습니다 (이는 기계 코드에 대한 조사가 필요합니다).

그러나이 모든 것들은 올바른 종류의 마음이 필요합니다. 당신이 넣을 수있는 사람이라면

while(x--)
{
  ...
}

일단 잘 사용하면 그것이 무엇을하는지 배우지 만 혼자서하는 일을 해결하기가 어렵다는 것을 알게되면 조립 언어는 아마도 시간 낭비 일 것입니다.

다른 팁

등록 할당 및 관리

어셈블리는 CPU가 동시에 저글링 할 수있는 변수 (기계 단어 크기의 정수)에 대한 좋은 아이디어를 제공합니다. 루프를 분해하여 몇 가지 임시 변수 만 포함되면 레지스터에 모두 적합합니다. 그렇지 않다면, 일이 메모리로 바뀌면서 루프가 천천히 실행됩니다.

이것은 C 코딩에 정말 도움이되었습니다. 나는 가능한 한 작은 스파게티로 모든 루프를 단단하고 단순하게 만들려고 노력합니다.

x86은 바보입니다

여러 어셈블리 언어를 배우면 x86 명령 세트가 얼마나 절름발이인지 알게되었습니다. 가변 길이 지침? 예측하기 어려운 타이밍? 비 정교회 주소 지정 모드? 어.

우리 모두가 MIPS, 또는 ARM 또는 PowerPC라고 생각한다면 세상이 더 나아질 것입니다. 또는 오히려, 인텔/AMD가 반도체 전문 지식을 가져 와서 멀티 코어, 초고속, 초기 마이프를 만드는 데 사용했다면 모든 교환 품질을 가진 X86 프로세서 대신 프로세서.

컴퓨터가 "후드 아래"작동하는 방식에 대해 더 나은 감사를 얻기 위해 어셈블리 언어를 아는 것이 좋으며, 무언가를 디버깅 할 때 도움이되며 디버거가 제공 할 수있는 모든 디버거가 조립 코드 목록으로 최소한 제공합니다. 문제가 무엇인지 알아낼 수있는 기회. 그러나 CPU가 지침을 운반하는 방법을 활용하고 컴파일러가 초 고효율 기계 코드를 생성하도록 강제로 높은 수준의 코드를 작성하는 것과 같은 고급 프로그래밍 언어에 저수준 지식을 적용하려고하면 마이크로 최적화를 시도하고 있다는 신호. 대부분의 경우 일반적으로 성능 게인이 필요하지 않으면 컴파일러를 능가하는 것이 일반적으로 더 좋습니다.

따라서 일이 어떻게 작동하는지 더 잘 이해하기 위해 조립을 아는 것이 좋지만, 얻은 지식이 고급 언어로 코드를 작성하는 방법에 반드시 직접적으로 적용되는 것은 아닙니다. 그러나이 메모에서 기능 호출이 어셈블리 코드 레벨에서 작동하는 방법 (스택 및 관련 레지스터에 대한 학습, 스택에서 매개 변수가 어떻게 전달되는지, 자동 스토리지 작동 방식을 배우는 등)를 배우고 있음을 알게되었습니다. "스택 공간"오류 및 "유효하지 않은 호출 규칙"오류와 같은 고급 코드에서 발생한 문제를 이해하기가 훨씬 쉽습니다.

가장 중요한 개념은 SIMD이며 창의적 사용입니다. SIMD를 올바르게 사용하면 문자열 처리에서 비디오 조작, 매트릭스 수학에 이르기까지 모든 다양한 응용 프로그램에서 엄청난 성능 이점을 제공 할 수 있습니다. 이곳은 당신이 극복 할 수있는 곳입니다 10 배의 성능은 순수한 C 코드보다 향상됩니다-이것은 어셈블리가 단순한 디버깅을 넘어 여전히 유용한 이유입니다.

내가 작업하는 프로젝트의 몇 가지 예 (모든 숫자는 핵심 2의 클록 사이클 카운트) :

역 8x8 H.264 DCT (주파수 변환) :

c: 1332
mmx: 187
sse2: 127

8x8 크로마 모션 보상 (Bilinear Interpolation Filter) :

c: 639
mmx: 144
sse2: 110
ssse3: 79

4 16x16 절대 차이 작업의 합 (모션 검색) :

c: 3948
mmx: 278
sse2: 231
ssse3: 215

(예, 맞습니다. C보다 18 배 빠릅니다!)

16x16 블록의 평균 제곱 오차 :

c: 1013
mmx: 193
sse2: 131

16x16 블록의 분산 :

c: 783
mmx: 171
sse2: 106

메모리, 레지스터, 점프, 루프, 이동 및 다양한 작업을 어셈블러에서 수행 할 수 있습니다. 나는 어셈블리 언어 수업 프로그램을 디버깅하는 시대를 놓치지 않습니다. 그들은 고통 스러웠습니다! - 그러나 그것은 확실히 나에게 좋은 기초를 주었다.

우리는 오늘날 우리가 사용하는이 모든 멋진 바지 (그리고 내가 사랑하는 것)가 결국이 모든 것들로 귀결된다는 것을 잊어 버렸습니다.

이제 우리는 어셈블러를 모르고 생산적이고 유리한 경력을 쌓을 수 있지만, 이러한 개념은 알아야 할 것이 좋습니다.

나는 어셈블리의 학습 재귀와 고리가 나에게 많이 가르쳐 준다고 말할 것이다. 그것은 내가 사용하는 언어의 컴파일러/통역사가 물건을 스택에 밀어 넣는 방법에 대한 기본 개념을 이해하게 만들었습니다. 또한 악명 높은 스택 오버플로를 악용하는 방법을 배웠습니다. (약간의 명령으로 C에서 놀랍게도 쉽습니다).

일상적인 상황에서 ASM을 사용하는 것 외에, 나는 조립이 가르쳐 준 개념 중 하나를 사용할 것이라고 생각하지 않습니다.

주소 지정 모드가 매우 중요하다고 말합니다.

내 알마 교인은 그것을 극단적으로 가져 갔고, x86에는 충분하지 않았기 때문에 우리는 내가 기억할 수있는 적어도 7 개 이상의 PDP11의 시뮬레이터에서 모든 것을 연구했습니다. 돌이켜 보면, 그것은 좋은 선택이었습니다.

타이밍

빠른 실행 :

  • 병렬 처리
  • 간단한 지침
  • 조회 테이블
  • 지점 예측, 파이프 링

저장에 대한 액세스를 느리게하기 위해 빠르게 :

  • 등록
  • 캐시 및 다양한 수준의 캐시
  • 메모리 힙과 스택
  • 가상 메모리
  • 외부 I/O

요즘 X86 ASM은 CPU의 내장에 대한 직접적인 선이 아니라 API입니다. 당신이 쓰는 어셈블러 opcodes 자체는 완전히 다른 명령 설정, 재 배열, 재 작성, 고정 및 일반적으로 인식을 넘어 엉망이된다.

따라서 Assembler 학습이 CPU 내부에서 무슨 일이 일어나고 있는지에 대한 근본적인 통찰력을 제공하는 것은 아닙니다. 어셈블러 학습보다 더 중요한 IMHO는 대상 CPU와 메모리 계층이 어떻게 작동하는지 잘 이해하는 것입니다.

이것 일련의 기사는 후자의 주제를 매우 철저히 다룹니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top