2016-09-24 5 views
3

그래서 내 ROT13 암호는 내가 원하는대로하고있다.하지만 결국 명령 프롬프트는 출력의 마지막 줄과 같은 줄에 나타난다. 이것은 어셈블리에서의 첫 프로젝트입니다. 그래서 내가 뭘 잘못하고 있는지 잘 모르겠습니다.ROT13 어셈블리의 어셈블리

+0

출력이 개행으로 끝나야합니다. (ASCII 코드 = 10). 너는 이미 너의 끈 중 하나에 너를 가지고있어. 별도의'write()'시스템 호출 대신에 아마도 사용자의 문자열을 저장하는 버퍼의 끝에 10을 저장하면됩니다. –

+3

BTW, 좋은 작업 서식 및 주석 달기 (및 기호 이름을 사용하여 더 적은 의견이 필요함). 이것은 초급 질문에 많은 코드 덤프보다 훨씬 읽기 쉽습니다. –

+0

_start에 'nop'이 필요하지 않습니다. 'start'와'_start' 심볼은 같은 주소를 가질 수 있습니다. 또는 'b _start'를 입력하여 거기에 중단 점을 설정할 수 있습니다. 재미있는 사실은'ld -e' 옵션으로 엔트리 포인트를 원하는 심볼 이름으로 설정할 수 있습니다 만, 그렇게하지 않으면 혼란을 일으킬 수 있습니다. 또한, 제거 된 바이너리에서는'readelf'를 사용하여 엔트리 포인트의 숫자 주소를 찾아서 거기에 중단 점을 설정할 수 있습니다. ('b * 0x04000 ...'). –

답변

0

프로그램은 출력 끝에서 개행을 인쇄하지 않으므로 종료 할 때 커서는 비어 있지 않은 행의 끝에 있습니다. 쉘은 이것을 모르고 다음 프롬프트를 출력합니다.

echo foo에는 줄 바꿈 줄이 포함되어 있으므로 셸에서 다음 프롬프트를 인쇄 할 때 커서가 이미 새 줄의 시작 부분에있었습니다. echo -n foo에는 후행 줄 바꾸기가 포함되어 있지 않으므로 커서가 foo으로 시작하는 줄 끝 부분에 놓이게되며 프로그램과 마찬가지로 프롬프트가 표시됩니다. 에코 명령을 hd으로 파이프하면 인쇄하는 ASCII 문자의 16 진수 덤프를 볼 수 있습니다.


그래서 해결책은 출력이 개행 (ASCII 코드 = 10)으로 끝나는 지 확인하는 것입니다. 이미 msg4: db 10, "Read error", 10 문자열에 있습니다. C에서`\ nRead error \ n '이라고 쓰지만 NASM 구문은 그렇게 작동하지 않습니다. 그것은 역 따옴표로 묶인 문자열 내에서 C 스타일 이스케이프를 지원하지만 사람들이 숫자 상수로 개행 문자를 작성하는 것이 일반적입니다.


귀하의 사용자 입력이 (당신이 sys_read에서 얻을) 일반적으로 사용자가 한 줄에 256 개 문자를 입력하거나 초기 읽어 수익을 만들기 위해 CTRL-D를 사용하지 않는 한, 개행 문자로 끝나야합니다. (또는 마찬가지로 개행 문자로 끝나지 않는 파이프 된 입력이므로 EOF를 읽음).

필자는 비교의 논리를 따르기 시작했지만 꽤 빨리 지쳤다. 귀하의 입력에서 줄 바꿈이 어떻게되는지 확신 할 수 없지만 귀하의 코드가 버퍼의 줄 바꿈을 수정 한 것으로 의심됩니다.. 당신은 아마 그것을 피하고 그것을 그대로 두어야합니다. 문자를 수정하지 않으려면 & 분기 비교 목록에 추가하는 것일 것입니다.

아마도 rot13 프로그램의 경우 버퍼 끝에 여분의 개행을 추가하거나 sys_write를 호출하여 단독으로 개행 문자를 인쇄하는 것이 좋습니다.


strace을 사용하여 시스템 호출을 테스트 할 수 있습니다. 예 : strace ./a.out은 사용자가 작성한 read() 및 write() 시스템 호출을 디코딩합니다.

디버깅 팁에 대한 자세한 내용은 태그 위키의 하단을 참조하십시오. (그 외에 많은 유용한 것들이 있습니다).


BTW, 모든 cmp al, '?'가 (일정/PMOVMSKB/테스트/JNZ으로 모든 XMM 레지스터 요소 및 PCMPEQB에 방송 AL) SSE2로하는 XMM 레지스터에 병렬로 비교들을 수행 할 수있다. 그러나 스칼라 코드를 잘 처리 할 때까지는 걱정하지 마십시오.


CMP의 쥐의 둥지를 피할 수있는 다른 방법은/JCC는 기본적으로 수정되지 않은 입력 문자를 떠나, 화이트리스트 알파벳 문자에있을 것이다.

그래서 다른 번호 또는 '+'하지만 '-' 등을 만 '1'를 블랙리스트 이유를 모르겠어요,하지만. 여기


내가 하나의 조건에 여러 유사한 조건을 축소하기 위해 일부 "고급"트릭, 루프을 구현하는 것입니다 방법입니다. isalpha()에 대한 부호없는 비교 트릭에 대한 설명은 내 대답 How to access a char array and change lower case letters to upper case, and vice versa을 참조하십시오.

;; ROT13 alphabetic characters. Copy others unmodified. 
;; Untested 
L1_top: 
    movzx eax, [esi]    ; get a character 
    inc  esi      ; update source pointer 

    mov  edx, eax    ; save a copy of the original 
    or  al, 0x20    ; make it lower-case if it's a letter (but we can still detect non-letters after this) 

    sub  al, 'a'     ; chars below 'a' will wrap to a high value 
    cmp  al, 'z'-'a' 
    ja  .non_alpha    ; jump if the sub wrapped, or the char was greater than 'z' 

    ; input char was alphabetic 
    sub  dl, 13     ; modify the original character 
    sub  al, 13     ; check if that takes us out of the alphabet. Can be a CMP, not SUB if we want. 
    jnc  .nocarry 
    add  dl, 26     ; add 26 if the subtract wrapped 
    ;add  al, 26     ; we don't care about the value in al anymore 
.nocarry: 

    ; dl = the ROT13'ed character, with its original case 
.non_alpha: 
    mov [edi], dl 
    inc edi 

    dec ecx      ; I'm not sure what all the cmp ecx,0 in various branches was for. Just do it earlier if necessary. 
    jnz L1_top 

원래 사실은 AL에서 낮은 맡았다 ROT13'ed 문자를 계산하고 그 원래 낮은 맡았다 문자의 차이를 발견하고 DL에 그 적용하려고 했어요. 그러나 그런 다음 초기 분기에서 DL을 조건부로 수정할 수 있음을 알게되었습니다.

;; after the or al,0x20: mov ah, al  ; don't over-do it with upper-half byte registers. False dependencies on AMD, and partial-reg merging stalls or slowdowns on pre-Haswell Intel if you're not careful. 

    add  al, 'a'     ; 'a' + al is the lower-cased ROT13 of the input character 
    sub  ah, al     ; ah = lcase(orig) - lcase(rot13) 
    sub  dl, ah     ; apply that delta to the original in dl 
    ; dl is the original character - 13 (plus 26 if necessary) 
+0

굵게 표시된 귀하의 의견은 정확히 무슨 일이 일어 났는지입니다. 또한, 나는 정말 내가 als 레지스터를 사용하여 많은 cmps을 가지고 싫어. 이것은 어셈블리에 처음으로 합법적 인 진출 이었기 때문에 지금까지는 더 나은 방법을 알지 못했지만 대단히 감사합니다! 당신의 통찰력으로 나는 훨씬 더 잘 이해하고 원래의 문제를 해결했습니다. – swingonaspiral

+0

@swingonaspiral : SSE 트릭 외에도, 컴파일러는 모두 같은 행동을 취하는 많은 사례가있는'switch()'문을 쓸 때 슬리브에 다른 트릭을 사용합니다. 예 : [gcc가 TEST에 대한 즉치 상수를 비트 맵으로 사용하는 방법] (https://godbolt.org/g/Htd9Gw)을 확인하십시오. (자세한 내용은 [이 답변에 대한 의견] (http://stackoverflow.com/a/129515/224132)을 참조하십시오.) –

+0

@swingonaspiral :하지만 실제로 멋진 트릭이없이 코드를 단순화하는 방법은 뒤로 물러나서 * 논리 *를 단순화하십시오. 그것은 ROT13이므로 알파벳 문자를 수정하고 * everything * else를 수정하지 않고 남겨두기를 원할 것입니다. 그래서 ** 보존하고 싶은 모든 것을 블랙리스트에 올리는 대신, 대문자와 소문자 알파벳 범위를 화이트리스트로 만드십시오. ** –

관련 문제