1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
| extern printf
SECTION .data name: db 'mrh929', 0 HelloCnss: db 'hello,cnss!', 10, 9 , "---%s", 10,0 str1: db "Let's start reading the assembly code!",10,0
enc: db 0,0,0,7,6,83,83,0,19,11,84,79,7,17,65,5,73,29,14,77,4,4,0,0,2,18,31,6,24,14,13,13,73,12,1,69,68,0,0,0 str2: db "Come on!",10,0 exp1: db "%s%s",0
str3: db "input your answer:",10,0 exp2: db "(%d + %d + %d + %d * %d - (%d >> 1)) ^ %d = ?", 10, "%s" ,0
SECTION .text global main
alter_str: //将edi指向字符串中的值都和esi指向字符串中的值进行异或一直到遇到0为止 push rbp //将rbp压入栈,保存堆栈 mov rbp, rsp //栈顶和栈底到一个位置 xor ecx, ecx //清空ecx的值
label: mov al, [edi+ecx] //将edi+ecx地址中的值放到al中 test al, al //进行与的操作,改变ZF标志位(结果为0,ZF 变成1),判断al是否为0 je quit //ZF标志位看上个语句的结果,ZF变成了1,就跳转到quit mov bl, [esi+ecx] //将esi+ecx中地址的值放到bl中 xor al, bl //将al与bl中的值进行异或 mov [edi+ecx], al //al中的值放入edi+ecx的地址中 add ecx, 1 //ecx进行+1 jmp label //跳转到label
quit: leave //还原堆栈 ret //还原函数
main: ;主函数从这里开始 push rbp //把rbp压入堆栈,保存堆栈 mov rbp, rsp //栈顶和栈底到一个位置 ;以上两行不需翻译
mov rdi, HelloCnss //将HelloCnss的地址放入rdi中 mov rsi, name //将name的地址放入rsi中 call printf //调用printf地址的函数,输出HelloCnss与name
mov rdi, str1 //将str1的地址放入rdi中 mov rsi, enc //将enc的地址,放入rsi中 call alter_str //调用alter_str地址的函数,用enc编码str1
mov rdi, exp1 //将exp1的地址放入rdi mov rsi, str1 //将str1的地址放入rsi mov rdx, str2 //将str2的地址放入rdx call printf //调用printf函数,用exp1来格式化输出str1与str2
; 翻译至此(包括alter_str)可得到 60% 的分数
mov rdi, exp2 //将exp2的地址放入rdi mov rsi, 1 //将1放入rsi中 mov rdx, 2 //将2放入rdx中 mov rcx, 3 //将3放入rcx中 mov r8, 4 //将4放入r8中 mov r9, 5 //将5放入r9中 push str3 //把str3放入堆栈 push 7 //7放入堆栈 push 6 //6放入堆栈
mov rax, 0 //rax清空 call printf //用exp2来格式化输出输出(1 + 2 + 3 + 4 * 5 - (6 >> 1)) ^ 7 = ? ,10,str3,0
; 翻译至此(包括alter_str) ; 并回答问题: ; 就linux下的C语言函数的传参方式而言,x86与x64下有什么区别? //64位linux下前6个参数用寄存器传入,后面的所有参数栈传入 //32位linux,都用栈传入 //_stdcall和_cdecl用push堆栈传参,而_stdcall来说push恢复堆栈的时候在调用函数里面,从而节省了代码的占用空间,_cdecl是在正常的调用函数外面进行了堆栈的恢复,_fastcall尽可能用mov寄存器传参提升了运算的速度,因为寄存器的运算速度很快,顺序从右到左 ; 可得到 100% 的分数
sub rsp, 10 //rsp-10,栈顶提升提供大小为10的空间 mov rax, 0 //将rax清空 mov rdi, 2 //将2放入rdi中 mov rsi, rsp //把rsp的值放入rsi,将栈顶的值保存到rsi中 mov rdx, 10 //将10放入rdx中 syscall //通过syscall来调用sys_read读取用户输入
; 以上部分要求准确答出该语句所调用的函数,不能用C语言的其他函数代替 ; 翻译至此(包括alter_str)可获得 120% 的分数
; prepare for fixing input lea rcx, [rsi] //把rsi地址中的值放入rcx中 add rcx, rax //rcs+rax
; 以上两行不用翻译
push 0x000a //把10压入堆栈 mov rdx, 0x2174686769722074 //!thgirt push rdx //rdx压入堆栈 mov rdx, 0x6f6e207369207325 //on si s% push rdx //rdx压入堆栈 mov rax, rsp //%s is not right!
mov rdx, 0x000a21746867 //!thg push rdx mov rdx, 0x6972207369207325 //ir si s% push rdx mov rbx, rsp //同上%s is right!
mov dl, [rsi] //将rsi中的值放入dl中 cmp dl, 0x31 //与1进行比较 jne eпd //如果输入的不是1,则跳到end mov dl, [rsi+1] //rsi地址加1的值放入dl中 cmp dl, 0x36 //与6进行比较 jne eпd //如果输入的不是6,则跳到end mov dl, [rsi+2] //rsi地址加2的值放入dl中 cmp dl, 0xa //将dl与0xa(16)进行比较 jne end //如果输入的不是16,则跳到end mov rdi, rbx //rbx放入rdi,rdi指向字符串%s is right! jmp stop //跳转到stop
end: mov rdi, rax //rdi指向字符串%s is not right!
stop: ; Fix the output sub rcx, 1 //rcx-1 mov byte [rcx], 0 ////字符串末尾添0 ; Show the result xor rax, rax //清空rax call priпtf //调用printf 输出结果is (not) right!
mov rax, 0 //rax清空 leave //还原堆栈 ret //还原原函数
;翻译全部(包括alter_str)可获得 150% 的分数
|