2012-04-24 1 views
2
부트 섹터를 작성하는 방법

최근 메신저 학습, 여기에 내가 배우고 전체 코드입니다 뭐죠 : 부팅하는 방법을 알고있는 경우어셈블리 "조직 XXXX"의 사용은

org 07c00h 
    mov ax, cs 
    mov ds, ax 
    mov es, ax 
    call DispStr 
    jmp $ 

DispStr: 
    mov ax, BootMessage 
    mov bp, ax 
    mov cx, 16 
    mov ax, 01301h 
    mov bx, 000ch 
    mov dl, 0 
    int 10h 
    ret 

BootMessage: db "Hello, OS!" 
times 510-($-$$) db 0 

dw 0xaa55 

매우 간단한 코드 시스템. 결과는 화면에 표시되는 Hello OS!이라는 줄입니다. 제가 알지 못하는 유일한 것은 첫 줄입니다 : org 07c00h,이 책은 코드 줄을 사용하여 컴파일러가 7c00h 자리에 주소를 찾을 수있게했지만 설명은 다음과 같습니다. 매우 애매한, 그리고 난 정말 모르겠다 여기에 그것의 사용은 뭐죠. 무슨 intheworld 라인 org 07c00h 여기합니까? 나는 그 줄을 지우려고하고, nasm을 사용하여 bin 파일을 만든 다음 bochs를 사용하여 bin 파일을 부팅합니다. 이전 버전과 다른 점은 없습니다 : "안녕하세요 OS!" 너무 화면에 표시됩니다. 첫 번째 라인이 아무것도하지 않는다고 말할 수 있을까요? intheworld org xxxx의 용도는 무엇입니까?

+0

정확하게 책의 내용을 의미합니다. 이해가되지 않는다면 기본 사항을 다시 검토해야합니다. 특히 메모리가 어떻게 작동하는지 이해해야합니다. –

+3

[nasm manual] (http://www.nasm.us/doc/nasmdoc7.html#section-7.1.1)은 "ORG 지시문의 기능은 NASM이 프로그램이 메모리에로드 될 때 시작됩니다. " 나는. 어셈블러가 독자적으로 알아낼 수없는 무언가를 말하고 있습니다. 프로그램의 어떤 주소에로드 될 것입니다. – user786653

+0

@ 칼 : 그리고 처음에는 도움이되고 친절한 것이 무엇인지 이해하고, 사람들로 하여금 열 받게하는 대신에 그들을 계몽하게하는 방법에 대해 이해해야합니다. – SasQ

답변

3

이것은 한 단계에서 어셈블러와 링커가있는 곳입니다. org는 링커에게 (이 경우 종종 동일한 프로그램에서) 링커에게 다음과 같은 코드를 넣을 실제 메모리 공간을 알려주는 어셈블러에게 알려줍니다. C 컴파일러 나 다른 고수준 언어 컴파일러를 사용하면 종종 컴파일러와 링크 단계가 따로 따로 있습니다 (컴파일러가 종종 뒤에서 링커를 호출 함). 소스는 링크 독립적 인 객체 파일로 컴파일되고 링크 단계에서 대기중인 일부 명령어는 실행되지 않습니다. 링커는 객체와 링커 스크립트 또는 메모리 공간을 설명하는 사용자 정보를 가져 와서 해당 메모리 공간에 대한 명령어를 인코딩합니다.

User786653 아주 잘 설정하면 지시 사항에 위치 종속 인코딩을 할 필요가있을 때를 대비하여이 명령어가있는 메모리 공간/주소를 자체적으로 알아낼 수없는 것을 어셈블러에 알려줍니다. 또한 주소 정보가 포함 된 바이너리 인 경우 출력 바이너리의 해당 정보를 사용합니다 (예 : elf, srec, ihex 등).

+0

thx,하지만'org 7c00h '는 무슨 뜻입니까? 세그먼트가 7c00h이거나 오프셋이 7c00h입니까? 어떤 도구를 사용하여 주소를 검색 할 수 있습니까? – Searene

+0

괜찮아요, bochs 디버거를 사용하면, 0x7c00h가 오프셋 주소 부분에 추가 된 것을 발견합니다. 첫 번째 줄이 없다면, 'org 07c00h' 시스템은 문자열'BootMessage'의 잘못된 주소를로드합니다. . 나는 많이 배웠다. – Searene

2

어셈블러가 귀하의 코드의 각 행을 프로세서 명령어로 변환하고 이러한 명령어를 생성합니다 출력 바이너리 파일에 순차적으로 차례로 출력합니다. 그런 다음 그는 0과 이상에서 시작하여 그러한 명령의 현재 주소를 세는 내부 카운터를 유지 관리합니다.

일반 프로그램을 어셈블하는 경우 이러한 지시 사항은 주소가 빈 슬롯이있는 일부 오브젝트 파일의 코드 섹션에서 끝나게됩니다.이 섹션은 나중에 링커에서 적절한 주소로 채워야하므로 그렇지 않습니다. 문제.

그러나 섹션, 재배치 및 기타 형식 지정없이 원시 이진 명령어를 사용하지 않고 플랫 바이너리 파일을 어셈블하는 경우 레이블을 나타내는 위치와 데이터 주소는 어셈블러에 대한 정보가 없습니다. 따라서 예를 들어 명령어 mov si, someLabel이있는 경우 어셈블러는 이진 파일의 시작 부분에서 0부터 시작하는이 레이블의 오프셋 만 계산할 수 있습니다. 즉, 코드 세그먼트에서 오프셋 0부터 시작하여 메모리에 코드가 있다고 가정합니다.

사실이 아니며 메모리에있는 기계 명령어가 다른 주소 (예 : 7C00이면 어셈블러에 소스의 시작 부분에 org 0x7C00을 쓰면 프로그램의 시작 주소가 7C00임을 알릴 필요가 있습니다. 이 지시문은 0 대신에 7C00에서 내부 주소 카운터를 시작해야한다고 어셈블러에 알립니다. 결과적으로 그러한 프로그램에 사용 된 모든 주소는 7C00만큼 이동합니다. 어셈블러는 각 레이블에 대해 계산 된 주소 각각에 7C00을 간단하게 추가합니다.예를 들어 이진 이미지 파일의 시작 부분에서 48 바이트 만 오프셋 되어도 레이블이 0048 (0000 + 48) 대신에 주소가 메모리에있는 것처럼 말합니다 (예 : 7C48 (7C00 + 48)). 오프셋 7C00에서로드하면 올바른 주소가 제공됩니다).

기타 질문 : 7C00은 부트 로더의 실제 주소입니다. 세그먼트가 겹치기 때문에이 물리적 주소를 다른 방식으로 논리적 주소 (세그먼트 : 오프셋)로 나타낼 수 있습니다 (다음 세그먼트는 이전 세그먼트 이후 16 바이트 (16 진수로 10)를 시작합니다). 예를 들어, 가장 간단한 구성 인 0000:7C00 논리 주소를 사용할 수 있습니다. 세그먼트 시작 부분에서 시작하여 0 세그먼트를 사용하고 0에서 오프셋 7C00을 사용합니다. 또는 논리 주소 07C0:0000 (7C0 번째 세그먼트)을 사용할 수 있습니다. 세그먼트는 서로 16 바이트 떨어져 시작한다는 것을 기억하십니까? 따라서 7C010 (십진수로 16)을 곱하면 7C00이됩니다. 16 진수 주소에서 오른쪽으로 한 자리 이동하는 문제입니다! :-) 이제 오프셋을 추가하십시오.이 시간은 0이므로 아직 물리적으로는 7C00입니다. 세그먼트 에있는 0 바이트는 메모리에서 7C00으로 시작합니다.

물론 당신은 또한, 같은 더 복잡한 주소를 사용할 수 있습니다 세그먼트가 2340에서 시작하고 당신이 그것을 오프셋 58C0를 추가 할 때, 당신은 다시 :-)하지만 그 일을 7C00를 얻을 수 있습니다 것을 의미한다 예를 들어, 0234:58C0에 대한 혼란 스러울 수 있습니다. 그것은 모두 필요한 구성에 달려 있습니다. 7C00 실제 주소를 세그먼트의 시작으로 간주하려면 세그먼트 07C0을 사용하고 첫 번째 명령어는 0 오프셋에 배치되므로 org 지시문을 입력 할 필요가 없으며 org 0을 입력 할 수 있습니다. 그러나 7C00 주소 아래에있는 일부 데이터를 읽거나 쓰려면 (예 : BIOS 데이터 또는 인터럽트 벡터로 바이올린을 들여다) 세그먼트 0 및 오프셋 7C00을 사용하십시오. 즉, 첫 번째 명령 (바이너리 파일의 0 번째 바이트)이 기억에있는 7C00 물리적 주소에 위치하십시오; 위에서 설명한 이유로 org 0x7C00 지시문을 추가해야합니다.