http://chortle.ccsu.edu/AssemblyTutorial/Chapter-16/ass16_1.html
이 장에서는 메모리로부터 레지스터에 로드(load)하는 명령들과 레지스터로부터 메모리에 스토어(store)하는 명령들에 대해 추가적으로 논해본다.
이 추가적인 명령들은 lw나 sw 명령보다 자주사용되지는 않는다.
장의 주제:
바이트(byte)를 로드하고 스토어하는 명령들: lb, lbu와 sb
하프워드(halfword)를 로드하고 스토어하는 명령들: lh, lhu, and sh
32비트 보다 작은 크기를 연산하기.
질문:
(복습) 주메모리에서 주소로 지정할 수 있는 가장 최소의 단위는 무었입니까?
1바이트 로드하기
http://chortle.ccsu.edu/AssemblyTutorial/Chapter-16/ass16_2.html
답: 1 바이트
메모리 주소로부터 1 바이트를 로드할 수 있는 2개의 명령이 있다. 주소는 워드를 로드하고 스토어하는 명령처럼 베이스 레지스터에 오프셋을 더해 실행시 계산된다. 각 명령은 32 비트 레지스터에 8비트 크기의 바이트를 집어넣는 방식에 따라 차이가 난다.
lb t,off(b) # $t <-- 부호가 연장된 바이트(Sign-extended byte)
# 메모리주소(b+off)
# b는 베이스 레지스터이다
# off는 16비트 크기의 2의 보수이다.
lb명령은 메모리로부터 레지스터의 하위 8비트에 바이트를 로드한다.하위 8비트는 레지스터의 0-7 비트이다. 로드한 뒤 비트7의 값이 레지스터 비트 8부터 31까지 복사된다(7 비트 왼쪽의 모든 비트들이 7비트의 값이 된다).
이것을 다른 방법으로 설명하자면 lb명령은 지정된 주소의 바이트를 32비트 부호 연장된(32-bit Sign-extended) 버전으로 레지스터에 로드한다.
바이트가 -128--+127의 범위의 8비트 부호있는 정수로 간주되고 그 바이트의 32비트 버전이 필요할 때 lb명령을 사용하자. 물론 32비트라도 정수 값에는 변화가 없다.
lbu t,off(b) # $t <-- 영으로 확장된 바이트(Zero-extended byte)
# 메모리주소(b+off)
# b는 베이스 레지스터이다
# off는 16비트 크기의 2의 보수이다.
lbu명령은 레지스터의 8-31을 0으로 채워 넣는다. lbu명령은 바이트가 ascii 문자이거나 8비트 부호없는 정수일때 사용된다.
질문:
메모리주소 0x10000007는 바이트 0xA4를 담고있다.
레지스터 0x10000000를 담고있다.
다음 명령이 실행된후 레지스터 $10은 어떤 값을 가지고 있습니까?
lb 10,7($8)
1 바이트 저장하기
http://chortle.ccsu.edu/AssemblyTutorial/Chapter-16/ass16_3.html
답:
0xFFFFFFA4
0xA4의 7번 비트는 1이다. 그러므로 lb명령은 레지스터 10번의 상위 비트들을 1로 연장한다.
1 바이트를 로딩하거나 스토하는것은 문서를 처리하는 경우 또는 어셈블러 프로그램이나 운영체제 프로그램같은 시스템 프로그램에 사용된다. 그래픽 프로그램에서도 1 바이트를 로드하거나 스토어하는 작동은 자주 사용된다. 물론 비트를 조작하는 명령을 같이써서 lw와 sw명령만으로 1 바이트를 로드하거나 스토어하는 작동을 할 수 있다. 하지만 바이트단위로 로드하고 스토어하는 명령을 사용하면 편리하다.
다음은 1 바이트를 스토어하는 명령이다.
sb t,off(b) # 레지스터 하위의 바이트를 off+b 주소에 저장한다.
# 레지스터 $t가 바이트를 담고있다.
# b는 베이스 레지스터이다.
# off는 16 비트 크기의 2의 보수로 표현된 정수 이다.
1 바이트를 저장하는데는 로드할때처럼 2개의 다른 명령이 필요하지 않다. 레지스터 하위의 바이트가 무었이든지 메모리에 복사된다.레지스터 나머지 부분의 비트는 무시된다. 물론 레지스터 내용 자체에 변화는 없다.
질문:
메모리주소 0x10000519는 바이트 0x44를 담고있다.
레지스터 0x10000400을 담고있다.
레지스터 0xFA034183을 담고있다.
메모리의 0x44 바이트 값을 0x83으로 바꾸는 명령을 작성해보자.
sb _, ( __ )
lb,lbu,sb 명령들은 정렬에 대한 제한이 없다. 메모리의 어떤 바이트도 프로그램의 테이터로 사용될 수 있다.대개 문자같은 경우 연속된 바이트로 저장되기 때문에 정렬제한이 없다는 것은 다행스러운 일이다.
로드와 스토어 명령은 여러 종류의 시스템이 사용하는 저장 미디어로부터 데이터를 입출력하는데 많이 사용된다. 한 정부기관에서 자기 테입에 기록한 데이터를 다른 종류의 컴퓨터를 사용하는 다른 정부기관에서 사용해야만할 경우가 종종 있다. 여러 시스템이 데이터를 공유할 수 있도록 데이터의 형식(format)으로 바이트의 순서를 정해놓는다. 데이터의 공유를 위해서는 컴퓨터마다 데이터를 읽고 쓰는 바이트 순서에 상관없이 저장 형식을 따라야만 한다.
질문:
특정한 데이터 테입 미디어는 빅엔디언 정수형식을 따르도록 제안한다. 테입의 입출력 버퍼(IO buffer)는 주소 0x10000000에서 시작한다. 레지스터 $9의 정수가 주소 0x10000000 에서 시작해서 4바이트를 저장할 수 있도록 다음 명령을 완성해 보자. MSB를 시작하는 주소에 집어넣어보자.
lui $8,0x1000 # $8은 베이스 레지스터를 담고있다.
sb $9,____($8) # LSB(least significant byte)
srl $9,$9,_____ # 다음 바이트를 하위로 옮긴다
sb $9,____($8) # 비트들은 8-15
srl $9,$9,_____ # 다음 바이트를 하위로 옮긴다
sb $9,____($8) # 비트들은 16-23
srl $9,$9,_____ # 다음 바이트를 하위로 옮긴다
sb $9,____($8) # MSB(most significant byte)
lui $8,0x1000 # $8은 베이스 레지스터를 담고있다.
sb $9,3($8) # LSB(least significant byte)
srl $9,$9,8 # 다음 바이트를 하위로 옮긴다
sb $9,2($8) # 비트들은 8-15
srl $9,$9,8 # 다음 바이트를 하위로 옮긴다
sb $9,1($8) # 비트들은 16-23
srl $9,$9,8 # 다음 바이트를 하위로 옮긴다
sb $9,0($8) # MSB(most significant byte)
레지스터의 최하위 바이트(LSB)는 sb명령이 필요한곳에 있기 때문에 먼저 메모리에 쓰여진다. 그리고 $9의 남은 바이트들은 가장 오른쪽 바이트까지 한 바이트씩 쉬프트 되면서 메모리로 쓰여진다. 완성된 프로그램이다:
## endian.asm
##
## $9를 빅 엔디언 순서로 메모리에 저장한다.
##
## 레지스터 사용:
## $8 --- 테이프 버퍼의 첫 바이트
## $9 --- 4바이트 정수
.text
.globl main
main:
lui $8,0x1000 # $8은 베이스 레지스터를 담고있다.
sb $9,3($8) # LSB(least significant byte)
srl $9,$9,8 # 다음 바이트를 하위로 옮긴다
sb $9,2($8) # 비트들은 8-15
srl $9,$9,8 # 다음 바이트를 하위로 옮긴다
sb $9,1($8) # 비트들은 16-23
srl $9,$9,8 # 다음 바이트를 하위로 옮긴다
sb $9,0($8) # MSB(most significant byte)
.data
tape: # 베이스 레지스터는 여기를 가리킨다
.space 1024 # 테이프 버퍼 (1K바이트)
## 파일의 끝
.space지정자는 메모리의 바이트들을 예약하는데, 이 경우 1024<10> 바이트를 예약한다. 이 공간이 테이프 레코더를 위한 버퍼라고 가정하자. 예제 프로그램은 첫 4바이트만을 사용한다.
질문:
.data섹션의 첫 바이트의 심볼릭 주소가 무엇 입니까? 실행시에 주메모리의 어떤 주소에 저장 되겠습니까?
프로그램 실행
http://chortle.ccsu.edu/AssemblyTutorial/Chapter-16/ass16_6.html
답: .data 섹션의 첫 바이트를 가리키는 심볼릭 주소는 tape이다. 실행시 주메모리의 주소는 0x10000000이다. 스핌어셈블러에서는 데이터 섹션의 첫바이트 주소 0x10000000가 주메모리주소(main storage address)의 기본값이다. 어셈블러 프로그램자체에서 이것을 지정하지는 않는다.
스핌은 가장 왼쪽에 MSB부터 시작하여 4바이트 워드 묶음으로 데이터를 보여준다. 사람이 읽기 편하게 워드 단위로 묶어 보여주는 것이다.각각의 4바이트 그룹 묶음안에서 가장 낮은 주소의 바이트가 오른쪽에 위치한다. 다음 그림은 레지스터의 첫바이트가 버퍼에 저장된 후 스핌의 상태를 보여준다.
attachment:endianRun.gif
주의깊게 살펴보면 바이트가 메모리상에 올바른 장소에 저장되었음을 볼 수 있다.
질문:레지스터 $9의 어떤 바이트가 0x10000000주소로 저장 되겠습니까?
하프워드 로딩하기(Loading Halfwords)
http://chortle.ccsu.edu/AssemblyTutorial/Chapter-16/ass16_7.html
답:
0x12 --- 빅엔디언 시스템에서는 정수의 빅엔드가 바이트 묶음의 첫번째 주소에 들어간다.
몇번의 오른쪽 쉬프트를 통해 그 자리로 도달한다.
MIPS에서 하프워드(halfword)는 2 바이트이다. 하프워드는 데이터 크기의 단위로 빈번히 사용된다. ANSI C의 경우 short 정수는 일반적으로 2 바이트이다. MIPS는 하프워드(halfword)를 로드하고 스토어하는 명령들을 가지고 있다.
하프워드(halfword)를 로딩하는 명령으로 2가지가 있다. lh 명령은 레모리에 있는 하프워드(halfword)의 부호비트(sign bit)를 가지고 레지스터 상위 2바이트를 언장한다. lhu 명령은 부호비트대신 영으로 연장한다.
lh t,off(b) # 부호연장된 하프워드를 레지스터 $t에 로드한다.
# 메모리 주소는 b+off 에서 시작한다.
# b는 베이스 레지스터이다.
# off는 16비트크기의 2의 보수이다.
lhu t,off(b) # 영으로 연장된 하프워드를 레지스터 $t에 로드한다.
# 메모리 주소는 b+off 에서 시작한다.
# b는 베이스 레지스터이다.
# off는 16비트크기의 2의 보수이다.
하프워드를 가리키는 주소들은 하프워드로 정렬되어져 있어야만 한다. 정렬되지 않은 주소에서 하프워드를 로드하려고 하면 트랩(trap)이 발생한다.
질문: 주소가 하프워드로 정렬되어 있는지 어떻게 알 수 있습니까?
하프워드 저장하기(Storing Halfwords)
http://chortle.ccsu.edu/AssemblyTutorial/Chapter-16/ass16_8.html
답:2의 배수 여부를 살펴본다. 하프워드로 정렬된 주소는 하위비트로 0을 가지고 있다.
하프워드를 저장하는 명령은 sh 하나만 있다. sh 저장명령은 지정된 레지스터의 상위 2바이트에 상관없이 레지스터의 하위 2 바이트를 메모리로 복사한다.물론 복사하는 레지스터의 데이터에는 변화가 없다.
sh t,off(b) # 레지스터 t의 하프워드를 주소 off+b로 저장한다.
#
# b는 베이스 레지스터
# off는 16비트 크기의 2의 보수.
MIPS연산 명령은 레지스터에 데이터가 어떻게 로드되었는가에 상관없이 항상 레지스터 전체 비트를 연산에 사용한다.
예를 들어 addu 명령에서 피연산자가 lh명령이나 lb명령으로 로드된 비트를 담고있는 레지스터 일지라도 레지스터 32비트 전체를 가지고 덧셈연산을 수행한다.
질문:
다음을 덧셈 연산 해보십시오.
http://chortle.ccsu.edu/AssemblyTutorial/Chapter-16/ass16_9.html
답:
attachment:arith32.jpg
MIPS에서 8비트 크기의 연산만 따로 수행하는 명령은 없다. 위에 보여진 것처럼 피연산자인 2레지스터가 바이트들을 담고있다고 가정해보자. 이 레지스터들을 워드크기로 덧셈연산하는 것은 8비트크기로 덧셈하는것과 같다고 볼 수 있다. 하지만 8비트에서 상위비트의 캐리값이 32비트 결과값에서는 8번 비트가 된다. 비트를 조작함으로써 이러한 문제들은 해결할 수 있다.
그러므로 하프워드나 8비트를 위한 특별한 연산 명령이 필요하지는 않다.
질문:
방금 계산한 덧셈결과를 2로 나누어보자. 오른쪽 쉬프트(right shift)를 사용하여 2로 나누어 보자.
32비트 결과 전체를 쉬프트 했을 때와 8비트만 쉬프트 했을때 위의 결과 값은 다르다. 물론 2로 나누기전에 32비트 합의 8번 비트의 캐리값을 미리 지웠다면 32비트 결과나 8비트 결과나 똑같았을 것이다.
일반적으로 여러번의 32비트 연산작동을 거친 하위의 바이트 값은 정말 8비트만 가지고 여러 연산작동을 거친 값이랑 다를 수 있다.
이러한 것이 컴파일러가 직면하는 문제이다. 예를들어 ANSI C에서 short의 정수값은 모든 컴퓨터에 동일한 방법으로 작동되어야한다. 하지만 16비트의 수학 연산이 모든 컴퓨터 구조에서 똑같이 작동하는 것은 아니다. C가 MIPS를 위해 컴파일 될때는 피연산자가 short 정수일 경우 각연산 명령 사이 사이에 몇가지 추가명령들을 집어넣는다. MIPS와 몇몇 다른계열의 컴퓨터에서 16비트 연산은 32비트 연산보다 훨씬 느리다.
순진한 초보 프로그래머는 작성하는 프로그램이 더빨리 작동하길 바라면서 short를 정수로 사용한다. 하드웨어와 컴파일러에 따라, 기대와 반대되는 결과를 가져올 수도 있다.
질문:
암호(Cryptography) 프로그램에서는 종종 문자를 8비트 정수로 간주하고 연산작동으로 문자를 암호화 합니다. 이 암호 프로그램은 윈도우 시스템에서 C언어로 작성 되었다고 가정해 봅시다 그런데 이 프로그램을 맥킨토시에서 컴파일해서 실행할 때 암호화된 결과가 다르게 나옵니다. 이제 여러분은 맥킨토시 버전의 프로그램이 윈도우의 버전과 동일한 암호파일을 산출하도록 임무를 부여 받았습니다. 이 문제를 해결하기위해 무었을 해야만 할까요?
16장 끝
http://chortle.ccsu.edu/AssemblyTutorial/Chapter-16/ass16_11.html
답:아마 두시스템사이에 작은 크기 정수의 연산 과정에서 차이가 있기 때문에 문제가 발생하는 것이다. 프로그램 내부의 변수 선언과 연산과정을 자세히 조사해야만 한다. 맥킨토시 버전의 결과가 윈도우 버전의 결과랑 같게 만들기 위해선 프로그램의 일부분을 어셈블리로 짜야만 할지도 모른다.
논의된 주제
Contents
메모리 접근 명령2
1바이트 로드하기
1 바이트 저장하기
공유되는 데이터
테입 라이터 (Tape Writer)
프로그램 실행
하프워드 로딩하기(Loading Halfwords)
하프워드 저장하기(Storing Halfwords)
모든 연산은 32비트 크기이다.
하위 결과값이 항상 정확한것은 아니다
16장 끝
Recent Posts
Archive Posts
Tags