어셈블리어(assembly language) 또는 어셈블러 언어(assembler language)는 기계어와 일대일 대응이 되는 컴퓨터 프로그래밍의 저급 언어이다. (wiki)
어샘블리어를 소개하기 전에 개발자가 C언어로 작성한 소스코드가 실제로 어떻게 실행되는지 알아보자. C언어 프로그램은 다음과 같은 순서로 작성되고 실행된다.
int s = 0;
for (i=0; i<10; i++) {
if (A[i]==0) continue;
s += A[i];
}
0x00000000 0x000009B3
0x00000004 0x00000A33
0x00000008 0x10000A97
0x0000000C 0xFF8A8A93
0x00000010 0x00A00E13
0x00000014 0x03CA5063
0x00000018 0x002A1513
0x0000001C 0x01550533
0x00000020 0x00052483
0x00000024 0x00048463
0x00000028 0x009989B3
0x0000002C 0x001A0A13
0x00000030 0xFE0002E3
어셈블리어는 기계어와 일대일 대응이 되는 low level 프로그래밍 언어이다.
따라서 컴파일러가 컴파일한 기계어는 어셈블리어와 일대일로 대응한다. 만약 개발자가 어셈블리어를 통해 프로그램을 작성할 경우, 프로그램의 동작을 instruction set 수준에서 완벽하게 제어할 수 있다.
0x00000000 0x000009B3 add x19 x0 x0
0x00000004 0x00000A33 add x20 x0 x0
0x00000008 0x10000A97 auipc x21 65536
0x0000000C 0xFF8A8A93 addi x21 x21 -8
0x00000010 0x00A00E13 addi x28 x0 10
0x00000014 0x03CA5063 bge x20 x28 32
0x00000018 0x002A1513 slli x10 x20 2
0x0000001C 0x01550533 add x10 x10 x21
0x00000020 0x00052483 lw x9 0(x10)
0x00000024 0x00048463 beq x9 x0 8
0x00000028 0x009989B3 add x19 x19 x9
0x0000002C 0x001A0A13 addi x20 x20 1
0x00000030 0xFE0002E3 beq x0 x0 -28
위의 c코드의 동작을 설명하면 다음과 같다.
int s = 0;
for (i=0; i<10; i++) {
if (A[i]==0) continue;
s += A[i];
}
이제 s라는 변수는 x19, i는 x20, A의 주소는 x21이라는 레지스터에 각각 저장되어 있다 가정하고, 다음과 같이 어셈블리 코드를 작성할 수 있다.
add x19 x0 x0 // s = 0
add x20 x0 x0 // i = 0
addi x28 x0 10 // x28 = 10
LOOP: bge x28 x20 EXIT // if 10 >= i; GOTO EXIT
slli x10 x20 2 // x10 = i * 4
add x10 x10 x21 // x10 = &A[0] + i*8
lw x9 0(x10) // x9 = A[i]
beq x9 x0 L1 // if A[i] == 0; GOTO L1
add x19 x19 x9 // s = s + A[i]
L1 : addi x20 x20 1 // i = i + 1
beq x0 x0 LOOP // GOTO LOOP
EXIT:
우선 s와 i를 나타네는 레지스터를 0(x0)로 초기화 하였다. bge는 상수를 비교하지 않고, register에 저장된 값을 비교하기 때문에, x28이라는 임시 레지스터를 만들어 숫자 10을 저장하였다. 3~4번 째 줄과, 뒤에서 3~2번 째 줄을 통해서 for (i=0; i<10; i++)
가 구현된다.
32bit riscv를 사용한다고 할 때, A[i]의 값은 다음과 같은 방식으로 load한다.
slli x10 x20 2 // x10 = i * 4
add x10 x10 x21 // x10 = &A[0] + i*8
lw x9 0(x10) // x9 = A[i]
Vscode의 RISC-V Venus Simulator Extention을 활용하여 작성한 assembly 코드를 시뮬레이션할 수 있다. (Venus simulator는 32bit riscv을 지원하기 때문에 load word를 사용하였다.)
위의 코드를 실행하면,
Loop를 반복하면서 x9, x19 레지스터에 적절한 값이 저장되고, loop가 예상한 순간 종료되는 모습을 확인할 수 있다.