이번엔 좀 더 어려운 arm 명령어 ldr/str 그리고 stack에 대해 알아보자. 1. LDR / STR with offsets 기본적으로 arm에서 메모리를 참조하는 연산은 LDR/STR이 전부이다. 이 명령어들에는 offset이 포함되는데, offset의 위치에 따라 기능이 다르다.(바로 뒤에 설명) 1) pre-indexed format pre-indexed format은 offset의 위치가 base register(rn) 과 같은 괄호 안에 포함되어있을 경우이다. 예를 들어 ldr r0, [r1, #12] , str r5, [r6, r7, lsl #2] 와 같은 경우 pre-indexed 라고 할 수 있겠다. pre-indexed는 rn의 값을 offset으로 이동한 위치에 있는 값을 연산한..
System Programming(ARM)
이번 챕터는 실생활에 아주 필요한 방법이다. 이걸 가지고 어셈블리어 실습 때 몰래 쓰윽 바꿔서 제출할 수도 있고, 틀린 부분을 보거나, 기계는 이 코드를 어떻게 처리할 지 알아볼 수 있어서 좋다. 이번에 알아볼 코드는 단 두가지 밖에 안된다. 첫 번째, 작성한 C 코드를 어셈블리어로 바꾸는 방법은 다음과 같다. "gcc -marm -O1 -c -o code.o code.c" 이 형식만 기억하면 된다. 두 번째, 바꾼 오브젝트 파일의 내용을 확인하는 방법은 다음과 같다. "objdump -d code.o" 바로 실습으로 넘어가보자. 1. sum 함수 c언어 코드 변환 과정 vi로 코드를 작성 후 다음과 같이 명령어를 입력한다. 어셈블러 코드 그다음 objdump 명령어를 치면 다음과 같은 화면이 나타난다...
이번 장에서는 Arm 프로세서에서 함수를 호출하거나, 인자를 전달하고 리턴되는 Register 들의 역할을 살펴보고 프로시저가 무엇인지 알아보자. 1. Procedure Call 형식 : BL 리턴 주소는 lr 레지스터에 저장된다. (리턴 주소란? 해당 명령어를 마치고 다음으로 갈 주소) "Label"로 jump 하는 의미를 갖는다. 예시 838c의 명령어가 실행될 때, 리턴 주소는 8390이며, lr에 들어가게 된다. 이후 프로시저가 끝나면 8390 줄이 실행되게 된다. 2. Procedure Return 프로시저 콜이 있다면, 당연히 리턴도 있어야 할 것이다. 여기서는 자연스러운 리턴 대신 직접 할 수 있는 방법을 설명한다. 1) bx 명령어 bx lr은 레지스터 lr에 담긴 주소 (가리키는 주소)로..
이번에 배울 Linking은 시스템 프로그래밍에서 대단히 중요한 역할을 수행하는 Linker(링커)가 하는 일이다. 이 단원에서 가장 중요한 것은 "다른 파일에 있는 함수를 어떻게 가져올 것인가?"가 문제가 되는데 천천히 살펴보자. 1. C 프로그래밍에서의 Linking C언어에서의 Linking 코드이다. extern 키워드를 이용해 main.c 파일에 있는 buf 배열을 가져와 사용하는 것을 볼 수 있다. 우리는 이 코드를 직전 단원에서 배운 C 코드를 어셈블러로 변환하는 방법을 이용해 변환해 볼 것이다. 그럼 한 번 불러 볼까요? 짜잔! 어셈블러로 바뀌었다! 왼쪽 코드를 실행하면 오른쪽 데이터가 저장되는데, 이전에 보지 못했던 명령어가 보인다. movw, movt 란? 기존 32비트를 움직일 수 없..
이 글은 “Computer Systems: A Programmer’s Perspective, Third Edition” 교재를 바탕으로 정리한 내용입니다. 이번에 배울 시스템 수준의 I/O (input-output) 장치는 Unix I/O 를 중심으로 알아갈 것이고 추가로 교재에서 나오는 RIO(robust), standard I/O 와 비교해 설명합니다. 1. Unix File Unix file은 바이트의 연속으로 구성되어 있다. ex. (B0 , B1 , · · · , Bk , · · · , Bm−1) 이 "파일"이라는 단어에는 우리가 사용하는 많은 I/O 디바이스가 포함되어 있는데, 대표적으로 디스크, 터미널, 커널 등이 있다. Unix File Types 유닉스 파일의 타입은 여러개로 나뉜다. R..
이번 Two-pass Assembler는 시스템 프로그래밍 과목에서 항상 텀 프로젝트로 나왔던 부분이다. 다른 학교도 그래서인지.. 구글에 "two-pass assembler in github"라고 치면, 아주 글로벌하게 프로젝트 코드가 나오는 것을 볼 수 있다 😀 어셈블러란? 말 그대로, 조각 난 것을 모아준다는 의미 어셈블리 언어로 작성된 코드를 기계어로 번역해줌 1대 1 대응이 일어난다. 기계어를 저장하는 방법 위로 올라갈수록 높은 주소 → 위로 올라가면서 저장이 된다. (little-endian 방식) ARM은 little, big 둘 다 지원하지만, 기본이 little으로 되어 있다. 예시) ARM Instruction Set Format 위 두 그림은 arm에서 어셈블리 코드를 기계어로 변환하..
이번에 배울 예외적인 흐름 제어는 일반적인 애플리케이션에서 처리하지 못하는 예외들을 OS로 넘겨 처리하는 기법을 말한다. 우선 이전에 배운 것들을 다시 상기해보자. 우리가 지금까지 배운 컴퓨터 시스템 안에서의 상호작용 Assembly language : 명령어 사이의 상호작용 Procedure calls : 함수 사이의 상호작용 Linking : 오브젝트 파일 사이의 상호작용 Control Flow(흐름 제어)란? 일반적인 컴퓨터는 프로그램이 시작하면 명령어들이 순차적으로 진행이 되고 끝나게 된다. 이러한 과정 속에서 CPU는 명령어를 한 번에 한 개씩 수행할 수 있게 되는데, 이 순서를 CPU의 Control Flow라고 한다. 만약 Control Flow가 제대로 동작하지 않는다면, 명령어들이 비순차..
이번엔 저번 시간에 배운 시그널을 c언어를 이용해 호출해보는 실습을 진행해보자. Signal 알아보기 : suhwanc.tistory.com/127 Signal Handler c언어에서는 함수 signal을 이용해 시그널을 핸들링하는 기능을 제공한다. signal 함수는 다음과 같이 생겼다. -> signal(int signum, sighandler_t *handler) 첫 번째 인자는 시그널의 고유 ID이고, 두 번째 인자는 앞의 시그널에 대한 처리 루틴이다. 헷갈려서 위에 쓰지 않았지만, 이 함수는 이전 핸들러의 주소 포인터가 리턴된다.(반환값 : sighandler_t*) 두 번째 인자로는 그냥 handler 자체가 올 수도 있고, 특별하게 2가지가 더 올 수 있는데 SIG_IGN 이 오면, 앞의 ..
이번에 배울 시그널은 특정 시스템에 한정된 용어가 아닌 운영체제 전반에서 쓰이는 용어이니 잘 알아두자. 우선 이전에 배운 것들을 다시 상기해보자. 우리가 지금까지 배운 컴퓨터 시스템 안에서의 상호작용 Assembly language : 명령어 사이의 상호작용 Procedure calls : 함수 사이의 상호작용 Linking : 오브젝트 파일 사이의 상호작용 Exceptions : OS와의 상호작용 (application -> OS) 결론부터 말하자면, 시그널은 application과의 상호작용을 의미하는데, 이는 application에 제어권을 넘긴다는 것을 의미한다. 말은 어려운 것 같지만 이후 나올 내용은 앞에서 배운 어떤 것보다 우리에게 친숙하게 느껴질 것이니 끝까지 잘 공부해보자. 시그널이란? ..
이번엔 ARM 어셈블리 코드로 작성한 파일을 디버깅하는 방법에 대해 알아보겠습니다. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 @ suhwan++20201108 @ debug practice .text _start: .global _start mov r1, #0 loop: cmp r1, #10 bge exit add r1, r1, #1 b loop exit: mov r0, #0 mov r7, #1 swi 0 .end cs 먼저, 이번에 사용할 코드입니다. 아주 단순하게 1부터 10까지 r1을 +1씩 증가시키고, 10이 되면 프로그램을 종료하는 코드입니다. 1. 디버그 옵션 설정 -> 디버그 옵션은 as(오브젝트 파일로 변환)할 때 "-g" 옵션을 설정하면 ..
이번엔 미리 버퍼에 저장해둔 문자열을 출력해봅시다! 순서는 다음과 같습니다. 1) 문자열의 주소(맨 앞 포인터)를 레지스터에 담습니다.(adr 명령어 사용) 2) 포인터를 하나씩 증가시키면서 바이트 단위로 로드해서 출력합니다. 3) 위 과정을 문장이 끝날 때까지 반복합니다. 소스 코드 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 @ suhwan++20201108 @ write sentence .text _start: .global _start adr r3, msg @ r3