c0mpos3r

Calculate string length 본문

Develop/Assembly

Calculate string length

음대생 2024. 7. 4. 14:24

문자열의 길이를 계산해야 하는 이유는 무엇인가

 

sys_write는 메모리에 출력할 문자열에 대한 포인터와 출력할 바이트 단위를 전달해야 한다. 메시지 문자열을 수정하려면 sys_write에 전달하는 바이트 단위의 길이도 업데이트해야 하며, 그렇지 않으면 올바르게 인쇄되지 않는다.

 

메시지 문자열을 ‘Hello brave new World’라고 수정한 다음 새 프로그램을 컴파일, 링크 및 실행한다.출력은 ‘Hello, brave’ (처음 13자)가 될 것이다. 왜냐하면 우리는 여전히 13바이트만 sys_write에 길이로 전달하기 때문이다. 이는 사용자 입력을 출력할 때 특히 필요하다.

 

이는 사용자 입력을 출력할 . 때 특히 필요하다. 프로그램을 컴파일할 때 데이터의 길이를 알 수 없으므로 성공적으로 출력하려면 런타임에 길이를 계산하는 방법이 필요하다.

 

Program Write

문자열의 길이를 계산하기 위해 포인터 연산이라는 기술을 사용한다. 메모리에서 동일한 주소를 가르키는 두 개의 레지스터가 초기화된다. 하나의 레지스터(이 경우 EAX)는 문자열의 끝에 도달할 때까지 출력 문자열의 각 문자에 대해 1바이트씩 앞으로 증가한다. 그러면 원래 포인터가 EAX에서 차감된다. 이는 사실상 두 배열 사이의 뺄셈과 같으며 그 결과 두 주소 사이의 요소 수가 산출된다. 이 결과는 하드 코딩된 개수를 대체하는 sys_write로 전달 된다.

 

CMP 명령어는 왼쪽과 오른쪽을 비교하고 프로그램 흐름에 사용되는 여러 플래그를 설정한다. 우리가 확인하는 플래그는 ZF 또는 제로 플래그이다. EAX가 가리키는 바이트가 0과 같으면 ZF 플래그가 설정된다. 그런 다음 ZF 플래그가 설정되어 있으면 JZ 명령어를 사용하여 프로그램에서 ‘완료’라고 표시된 지점으로 점프한다. 이는 다음 문자 루프에서 벗어나 나머지 프로그램을 계속 실행하기 위한 것이다.

 

helloworld-len.asm

; Hello World Program (Calculating string length)
; Compile with: nasm -f elf helloworld-len.asm
; Link with (64 bit systems requitre elf_i386 option_ : ld -m elf_i386 helloworld-len.o -o helloworld-len
; Run with: ./helloworld-len

SECTION .data
msg     db    'Hello, brave new world!', 0Ah ; 이제 프로그램의 다른 곳을 업데이트 하지 않고도 이 기능을 수정할 수 있다.

SECTION .text
global  _start

_start:

    mov     ebx, msg       ; 메세지 문자열의 주소를 EBX로 이동한다. 
    mov     eax, ebx       ; EBX의 주소도 EAX로 이동한다(이제 둘 다 메모리에서 동일한 세그먼트를 가리킨다.
    
nextchar:
    
    cmp     byte [eax], 0  ; 이 주소에서 EAX가 가리키는 바이트와 0을 비교한다(0은 문자열 구분 기호의 끝이다.)
    jz      finished       ; 코드에서 'finished'라고 표시된 지점으로 이동한다(0 플래크가 설정된 경우)
    inc     eax            ; EAX의 주소를 1바이트씩 증가시킨다 (0 플래그가 설정되지 않은 경우)
    jmp     nextchar       ; 코드에서 'nextchar'라고 표시된 지점으로 이동한다.
    
finished: 
    sub     eax, ebx       ; EAX의 주소에서 EBX의 주소를 뺀다.
                           ; 두 레지스터가 같은 주소를 가리키기 시작했음을 기억하자 (15줄 참조)
                           ; 하지만 메시지 문자열의 각 문자에 대해 1바이트씩 증가했다. 
                           ; 하나의 메모리 주소를 같은 유형의 다른 메모리 주소에서 뺄 때
                           ; 결과는 그 사이의 세그먼트 수(이 경우 바이트 수)이다.
                           ;
     mov    edx, eax       ; 이제 EAX는 문자열의 바이트 수와 같다.
     mov    ecx, msg       ; 나머지 코드는 익숙한 코드일 것이다.
     mov    ebx, 1         ;
     mov    eax, 4         ;
     int    80h            ;
     
     mov    ebx, 0         ;
     mov    eax, 1         ;
     int    80h            ;

 

 

Result

~$ nasm -f elf helloworld-len.asm
~$ ld -m elf_i386 helloworld-len.o -o helloworld-len
~$ ./helloworld-len
Hello, brave new world!

 

이 글은 https://asmtutor.com/#lesson3의 자료를 참고하여 작성되었습니다.

이 글은 상업적 목적이 아닌 개인이 공부한 내용을 정리하기 위한 글입니다. 

'Develop > Assembly' 카테고리의 다른 글

NULL terminating bytes  (0) 2024.07.04
External include files  (0) 2024.07.04
Subroutines  (0) 2024.07.04
Proper program exit  (0) 2024.07.04
Hello, world!  (0) 2024.07.04