그래서 내 ROT13 암호는 내가 원하는대로하고있다.하지만 결국 명령 프롬프트는 출력의 마지막 줄과 같은 줄에 나타난다. 이것은 어셈블리에서의 첫 프로젝트입니다. 그래서 내가 뭘 잘못하고 있는지 잘 모르겠습니다.ROT13 어셈블리의 어셈블리
답변
프로그램은 출력 끝에서 개행을 인쇄하지 않으므로 종료 할 때 커서는 비어 있지 않은 행의 끝에 있습니다. 쉘은 이것을 모르고 다음 프롬프트를 출력합니다.
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() 시스템 호출을 디코딩합니다.
디버깅 팁에 대한 자세한 내용은 x86 태그 위키의 하단을 참조하십시오. (그 외에 많은 유용한 것들이 있습니다).
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)
굵게 표시된 귀하의 의견은 정확히 무슨 일이 일어 났는지입니다. 또한, 나는 정말 내가 als 레지스터를 사용하여 많은 cmps을 가지고 싫어. 이것은 어셈블리에 처음으로 합법적 인 진출 이었기 때문에 지금까지는 더 나은 방법을 알지 못했지만 대단히 감사합니다! 당신의 통찰력으로 나는 훨씬 더 잘 이해하고 원래의 문제를 해결했습니다. – swingonaspiral
@swingonaspiral : SSE 트릭 외에도, 컴파일러는 모두 같은 행동을 취하는 많은 사례가있는'switch()'문을 쓸 때 슬리브에 다른 트릭을 사용합니다. 예 : [gcc가 TEST에 대한 즉치 상수를 비트 맵으로 사용하는 방법] (https://godbolt.org/g/Htd9Gw)을 확인하십시오. (자세한 내용은 [이 답변에 대한 의견] (http://stackoverflow.com/a/129515/224132)을 참조하십시오.) –
@swingonaspiral :하지만 실제로 멋진 트릭이없이 코드를 단순화하는 방법은 뒤로 물러나서 * 논리 *를 단순화하십시오. 그것은 ROT13이므로 알파벳 문자를 수정하고 * everything * else를 수정하지 않고 남겨두기를 원할 것입니다. 그래서 ** 보존하고 싶은 모든 것을 블랙리스트에 올리는 대신, 대문자와 소문자 알파벳 범위를 화이트리스트로 만드십시오. ** –
- 1. 어셈블리의 Maven 어셈블리
- 2. 어셈블리 언어로 된 Rot13 난독 화가 올바르게 작동하지 않습니다.
- 3. 어셈블리 란 무엇이며이 어셈블리의 용도는 무엇입니까?
- 4. ROT13/captain crunch 계속
- 5. Rot13-Implementation 정보
- 6. ROT13 코드의 오류 (C)
- 7. 간단한 rot13 인코더 vb.net
- 8. 어셈블리의 이름이
- 9. 어셈블리의 모듈
- 10. C++ ROT13 함수가 충돌 함
- 11. Javascript에서 "rot13"은 무엇을 의미합니까?
- 12. ROT13/47 ilk의 열쇠가없는 암호
- 13. 이것이 어셈블리의 올바른 정의입니까?
- 14. 어셈블리의 부동 소수점
- 15. WF에서 동일한 어셈블리의 여러 버전을 실행하려면 어셈블리 이름을 강하게 사용해야합니까?
- 16. .NET .. 런타임 오류 "어셈블리의 매니페스트 정의가 어셈블리 참조와 일치하지 않습니다."
- 17. 플러그인, 워크 플로우 및 지원 어셈블리의 어셈블리 경로
- 18. MVC4 : 어셈블리의 매니페스트 정의가 어셈블리 참조와 일치하지 않습니다.
- 19. CrmSvcUtil : 찾은 어셈블리의 매니페스트 정의가 어셈블리 참조와 일치하지 않습니다.
- 20. 어셈블리 및 다른 어셈블리의 리소스 이해에 문제가 있습니다.
- 21. 어셈블리의 C++ 클래스 함수
- 22. 어셈블리의 MOV 명령어 유효성
- 23. 현재 어셈블리의 경로 얻기
- 24. 어셈블리의 변환
- 25. 두 개의 다른 어셈블리 버전 "찾은 어셈블리의 매니페스트 정의가 어셈블리 참조와 일치하지 않습니다."
- 26. gcc 어셈블리의 함수 재정렬
- 27. 동일한 어셈블리의 다른 버전 참조
- 28. 어셈블리의 전체 이름 얻기
- 29. 어셈블리의 스레드 로컬 스토리지
- 30. x86 어셈블리의 COM?
출력이 개행으로 끝나야합니다. (ASCII 코드 = 10). 너는 이미 너의 끈 중 하나에 너를 가지고있어. 별도의'write()'시스템 호출 대신에 아마도 사용자의 문자열을 저장하는 버퍼의 끝에 10을 저장하면됩니다. –
BTW, 좋은 작업 서식 및 주석 달기 (및 기호 이름을 사용하여 더 적은 의견이 필요함). 이것은 초급 질문에 많은 코드 덤프보다 훨씬 읽기 쉽습니다. –
_start에 'nop'이 필요하지 않습니다. 'start'와'_start' 심볼은 같은 주소를 가질 수 있습니다. 또는 'b _start'를 입력하여 거기에 중단 점을 설정할 수 있습니다. 재미있는 사실은'ld -e' 옵션으로 엔트리 포인트를 원하는 심볼 이름으로 설정할 수 있습니다 만, 그렇게하지 않으면 혼란을 일으킬 수 있습니다. 또한, 제거 된 바이너리에서는'readelf'를 사용하여 엔트리 포인트의 숫자 주소를 찾아서 거기에 중단 점을 설정할 수 있습니다. ('b * 0x04000 ...'). –