[原 文] 어 셈 블 리 프로 그래 밍: Hello World!상해. - 좋 은 글!!
7714 단어 컴퓨터 언어
준비 작업
CPU 명령 실행 과정
1. 손가락질
2. 디 코딩
3. 집행
4. 다시 쓴다
이해 레지스터
우리 의 소스 코드 를 분석 하 다
총괄 하 다
원본 링크 주소:http://os-blog.com/x86-64-assembly-programming-hello-world/
번역문 주소:https://www.cnblogs.com/lazycoding/archive/2012/01/02/2310049.html
첫 번 째 번역, 잘못된 점 은 원우 들 이 아낌없이 가르쳐 주 기 를 바 랍 니 다.
만약 당신 이 자신의 운영 체 제 를 구축 하려 고 한다 면 (곧 할 것 입 니 다. 그래 요?) 어 셈 블 리 프로 그래 밍 에 익숙해 져 야 합 니 다. 어 셈 블 리 언어 를 알 게 되면 완전한 OS 를 만 들 수도 있 습 니 다. 어떻게 선택 하 든 본 튜 토리 얼 은 x86 - 64 어 셈 블 리 언어 를 소개 하고 나중에 '어 셈 블 리 프로 그래 밍' 시 리 즈 를 내 놓 을 것 입 니 다.좀 더 고 급 스 러 운 이 야 기 를 할 겁 니 다.
본 시리즈 의 글 을 받 을 수 있 도록 rss 나 email 을 통 해 제 블 로 그 를 구독 하 시 는 것 을 환영 합 니 다.
준비 작업
우리 가 시작 하기 전에 당신 은 x86 한 대가 필요 합 니 다.64 의 Liux 기계, 그리고 nasm 프로그램 이 설치 되 어 있 습 니 다. nasm 를 다운로드 하고 설치 할 수 있 을 것 이 라 고 생각 합 니 다.만약 당신 이 아직 Liux 기계 가 없다 면 본 고 를 참조 하여 가상 컴퓨터 에 Liux 를 설치 하 십시오.
"Hello World!"
대부분의 프로그램 언어의 시작 튜 토리 얼 처럼 우 리 는 가장 기본 적 인 hello World 프로그램 으로 시작 할 것 입 니 다. 나 는 코드 를 보 여 주 는 것 을 통 해 직접 입력 하고 붙 여 넣 기 를 복사 하지 말 라 고 건의 합 니 다.
우선, 작업 파일 을 저장 할 디 렉 터 리 를 만 듭 니 다.
$ mkdir asm-tutorial
$ cd asm-tutorial
$ gedit hello-world.asm
위의 예 에서 저 는 gedit 로 hello - world. asm 를 열 었 습 니 다. 이것 은 사용 하기 좋 고 통용 되 는 텍스트 편집기 입 니 다. 그러나 emacs, vim 또는 다른 텍스트 편집기 도 자 유 롭 습 니 다.
자, 이제 우 리 는 우리 의 hello World 프로그램 에 코드 를 입력 합 니 다. 당신 이 이미 완성 하고 컴 파일 에 성공 한 후에 나 는 코드 가 어떻게 작 동 하 는 지 설명 할 것 입 니 다.
[bits 64]
global _start
section .data
message db "Hello, World!"
section .text
_start:
mov rax, 1
mov rdx, 13
mov rsi, message
mov rdi, 1
syscall
mov rax, 60
mov rdi, 0
syscall
실행 가능 한 파일 만 들 기
입력 이 완료 되면 파일 을 저장 하고 터미널 에 아래 명령 을 입력 하 십시오.
$ nasm -f elf64 hello-world.asm
$ ld hello-world.o -o hello-world
$ ./hello-world
Hello, World!%
첫 번 째 줄 nasm - f elf 64 hello - world. asm 은 nasm 프로그램 이 우리 의 파일 을 어 셈 블 리 하 는 것 을 알려 주 었 습 니 다. - f elf 64 는 nasm 에 elf 64 형식의 대상 파일 을 만 들 고 싶다 는 것 을 설명 합 니 다.
nasm 는 우리 가 알 고 있 는 바 와 같이 어셈블러 입 니 다. 어셈블러 는 어 셈 블 리 언어 로 작 성 된 파일 입 니 다. 마치 우리 의 hello - world. asm 을 기계 코드 로 바 꾸 는 것 과 같 습 니 다. 기계 코드 는 컴퓨터 에 어떤 조작 을 수행 하 는 지 알려 줍 니 다. nasm 에서 생 성 된 파일 을 목표 파일 이 라 고 합 니 다. 이 작은 예 에서 nasm 은 hello - world. o 라 는 파일 을 만 듭 니 다.
우 리 는 hexdump 도구 로 우리 의 목표 파일 의 내용 을 보 았 다.
$ hexdump hello-world.o
...
0000080 0001 0000 0001 0000 0003 0000 0000 0000
0000090 0000 0000 0000 0000 0200 0000 0000 0000
00000a0 000f 0000 0000 0000 0000 0000 0000 0000
00000b0 0004 0000 0000 0000 0000 0000 0000 0000
00000c0 0007 0000 0001 0000 0006 0000 0000 0000
00000d0 0000 0000 0000 0000 0210 0000 0000 0000
...
보 셨 죠? 기계 코드 는 과감하게 기 계 를 위 한 것 이지 사람 을 위 한 것 이 아 닙 니 다.
이 프로그램 을 실행 시 키 는 마지막 단 계 는 linking 입 니 다. 링크 는 시스템 링크 기 에 의 해 이 루어 집 니 다. Liux 에서 이 도 구 는 ld 라 고 합 니 다. linking 은 대상 파일 을 조합 하여 실행 가능 한 파일 로 변환 하 는 것 입 니 다.
- o hello - world 이 옵션 은 ld 에 게 우리 가 만 들 고 싶 은 실행 가능 한 파일 이름 을 hello - world 라 고 알려 주 는 것 입 니 다.
마지막 으로 우 리 는 우리 의 파일 이름 전에 ". /" 를 추가 하여 프로그램 을 실행 합 니 다. 프로그램 은 Hello, World 로 돌아 갑 니 다!
CPU 명령 실행 과정
우리 가 우리 의 프로그램 을 깊이 발굴 하고 분석 하기 전에 CPU 가 실행 하면 매우 좋 은 점 을 알 아 보 자. 일반적으로 CPU 의 목적 은 의미 있 는 명령 서열 을 집행 하 는 것 이다. 보통 네 단계 로 나 뉘 는데 손가락, 디 코딩, 실행, 쓰기 이다.
1. 손가락질
첫 번 째 단 계 는 프로그램 메모리 에서 명령 을 꺼 내 는 것 을 포함 하고 명령 이 메모리 에 있 는 위 치 는 프로그램 카운터 (PC) 에서 지정 하 며 명령 이 나 오 면 프로그램 카운터 가 다음 명령 을 가리 키 는 것 을 말한다.
2. 디 코딩
디 코딩, CPU 가 어떤 작업 을 수행 할 지 확인 합 니 다. 명령 은 보통 두 부분 으로 나 뉘 는데, 작업 코드 는 실행 할 동작 을 지정 합 니 다. 나머지 부분 은 이 작업 을 수행 하 라 는 정 보 를 제공 합 니 다. 상수, 레지스터 또는 메모리 주소 일 수 있 습 니 다. (작업 수 참조)
3. 집행
이전 단계 가 완 료 된 후에 실행 단계 에 들 어가 기 시 작 했 습 니 다. CPU 의 각 부분 은 서로 연결 되 어 조작 코드 가 지정 한 작업 을 수행 할 수 있 도록 합 니 다.그리고 실행
4. 다시 쓴다
마지막 단 계 는 실행 결 과 를 하나의 저장 주소 에 기록 하 는 것 입 니 다. 예 를 들 어 레지스터 나 메모리 주 소 는 모든 명령 에 출력 값 이 있 는 것 이 아 닙 니 다. 일부 명령 조작 프로그램 카운터 라 고 합 니 다. 이런 주 소 는 점프 명령 이 라 고 합 니 다. jmp 명령 은 순환, 조건문 과 함수 호출 을 간단 하 게 합 니 다.
이해 레지스터
레지스터 는 cpu 내부 의 소 용량 메모리 입 니 다. 우리 가 관심 을 가 지 는 것 은 주로 세 가지 레지스터, 데이터 레지스터, 주소 레지스터 와 유 니 버 설 레지스터 입 니 다.
어 셈 블 리 프로그래머 들 은 대부분 이 레지스터 를 조작 하고 있다.
우리 의 소스 코드 를 분석 하 다
위의 배경 지식 을 가지 게 되 었 습 니 다. 우 리 는 지금 우리 의 코드 를 분석 하고 있 습 니 다. 나 는 프로그램 을 여러 소절 로 나 누 어 모든 단계 에서 어떤 조작 을 완 성 했 는 지 설명 할 것 입 니 다.
[bits 64]
우리 프로그램의 첫 줄 은 어 셈 블 리 명령 입 니 다. 당신 이 추측 한 바 와 같이 이것 은 nasm 에 게 64 비트 프로세서 에서 실행 할 수 있 는 코드 를 얻 고 싶다 는 것 을 알려 주 는 것 입 니 다.
global _start
이 줄 은 다른 어 셈 블 리 명령 입 니 다. nasm 용start 표 시 된 코드 세그먼트 (section) 는 전역 적 으로 봐 야 합 니 다. 전역 적 인 부분 은 보통 다른 대상 파일 을 참조 할 수 있 습 니 다. 이 예 에서 저 희 는start 단 계 는 링크 기 가 프로그램 이 어디에서 시작 되 는 지 알 수 있 도록 전역 으로 표 시 됩 니 다.
section .data
message db "Hello, World!"
위의 코드 의 첫 줄 은 또 하나의 어 셈 블 리 명령 으로 nasm 뒤에 따 르 는 코드 는 data 세그먼트 이 고 data 세그먼트 는 전체 와 정적 변 수 를 포함 합 니 다.
다음 문장 에서 우 리 는 이러한 정적 변 수 를 가지 고 있다.message db "Hello, World!", db 는 데이터 초기 화 를 설명 하 는 데 사 용 됩 니 다. message 는 변수 이름 으로 "Hello, World!" 와 연 결 됩 니 다.
section .text
위 에 있 는 이 문장 은 다른 단락 의 명령 섹 션 입 니 다. 그러나 이번 에는 nasm 에 게 뒤 따 르 는 코드 를 text 세그먼트 에 저장 하 라 고 알려 줍 니 다. text 세그먼트 는 가끔 code 세그먼트 라 고도 부 릅 니 다. 실행 가능 한 코드 를 포함 한 대상 파일 의 일부분 입 니 다.
마지막 으로 우 리 는 이 프로그램의 가장 중요 한 부분 에 도착 해 야 한다.
_start:
mov rax, 1
mov rdx, 13
mov rsi, message
mov rdi, 1
syscall
mov rax, 60
mov rdi, 0
syscall
첫 줄.start:, 그 뒤의 코드 와start 태그 가 연결 되 어 있 습 니 다.
mov rax, 1
mov rdx, 13
mov rsi, message
mov rdi, 1
위의 네 줄 은 모두 다른 레지스터 에 불 러 오 는 값 입 니 다. RAX 와 RDX 는 모두 유 니 버 설 레지스터 입 니 다. 우 리 는 각각 1 과 13 을 저장 합 니 다. RSI 와 RDI 는 소스 와 대상 데이터 색인 레지스터 입 니 다. 우 리 는 소스 레지스터 RSI 가 message 를 가리 키 고 대상 레지스터 는 1 을 가리 키 도록 설정 합 니 다.
현재 레지스터 가 불 러 온 후에 우 리 는 syscall 명령 이 있 습 니 다. 이것 은 컴퓨터 에 우리 가 레지스터 에 불 러 온 값 을 사용 하여 시스템 호출 을 실행 하고 자 하 는 것 을 알려 주 는 것 입 니 다. 우리 가 불 러 온 첫 번 째 숫자 는 바로 RAX 레지스터 의 값 입 니 다. 컴퓨터 에 우리 가 어떤 시스템 호출 을 사용 하고 싶 은 지 알려 주 는 것 입 니 다. syscalls 표 와 해당 하 는 숫자 는 이곳 을 조회 할 수 있 습 니 다.
니 가 그 시계 에서 본 것 처럼RAX 의 1 은 write (int fd, const void * buf, size t bytes) 를 호출 하려 는 것 을 의미 합 니 다. 다음 명령 은 mov rdx, 13 입 니 다. 우리 가 호출 하고 자 하 는 함수 write () 의 마지막 매개 변수 값 입 니 다. 마지막 매개 변수 sizet bytes 는 message 의 크기 를 명령 합 니 다. 여기 13 이 바로 "Hello, World!" 의 길이 입 니 다.
다음 두 명령 은 mov rsi, message 와 mov rdi, 1 은 각각 다른 두 개의 매개 변 수 를 만 들 었 기 때문에 우 리 는 그들 을 함께 놓 고 syscall 을 실행 하려 고 할 때 우 리 는 컴퓨터 에 write (1, message, 13) 를 실행 하 라 고 알려 주 었 다. 1 은 표준 출력 stdout 이기 때문에 이 질 적 으로 우 리 는 컴퓨터 에 message 에서 13 개의 바이트 를 꺼 내 stdout 으로 출력 하 라 고 알려 주 었 다.
mov rax, 60
mov rdi, 0
syscall
지금, 당신 은 우리 가 이미 모든 기능 을 실 행 했 는 지 알 고 싶 을 것 입 니 다. 왜 뒤에 syscall 이 있 는 지 알 고 싶 을 것 입 니 다. 당신 은 추측 할 필요 가 없습니다. 앞에서 말 한 그 시 계 를 직접 찾 아 보 세 요. 우 리 는 알 고 있 습 니 다. 60 참조 exit (). 왜냐하면 syscall 은 사실은 exit (0) 를 호출 하 는 것 이기 때 문 입 니 다.
총괄 하 다
그래서 우리 어 셈 블 리 프로그램의 첫 번 째 부분 은 message 변 수 를 'Hello, World!' 와 대응 시 키 는 것 입 니 다. 그리고 프로그램의 관건 적 인 부분 은 두 개의 syscall 을 쓰 는 것 입 니 다. 하 나 는 write () 이 고 다른 하 나 는 exit () 입 니 다. 그들 을 함께 두 는 것 입 니 다. 어 셈 블 리 프로그램 을 c 언어 로 번역 하려 면 아마 이렇게 보일 것 입 니 다.
int main()
{
char* message = "Hello, World!"
write(1, message, 13);
exit(0);
}
저작권 성명:http://www.cnblogs.com/lazycoding번역작가 의 노동 을 존중 하고 전재 할 때 이 성명 과 작가 의 블 로그 링크 를 보류 하 십시오. 감사합니다!