Complete the following: Answer the questions embedded in the sample code above.
- Instructor Question 1: Why is (W * Y) equal to (W
- Instructor Question 2: Why is (Z / Y) equal to (N >> Z) ?
- Instructor Question 3: Why do we do this; i.e. adding 0 to the number?
- Instructor Question 4: What are we doing here?
Modify the code such that if Z = 0x20, then what does N need to equal so that (X * Y) = (X > Z)
- Capture screenshots of your source code compiling and executing
- Include a line-by-line explanation of the code; i.e. what each instruction is doing and why
codingground Compile and Execute Assembly Online (Nasm v2.13.01) SIMPLY EASY ODDING _exit Execute > Share main.asm STDIN 1 Bitwise operations: AND, OR, NOT, shifting (to multiply and divide) %ifdef _WINDOWS %xdefine SECTION HDR segment %xdefine _START__ __main main %xdefine EXIT extern GetstdHandle@4 extern WriteFile@20 extern _ExitProcess@4 %else %xdefine SECTION_HDR section %xdefine START__ _start %xdefine _EXIT_ _exit 13 %endif CR dd db X _SECTION_HDR_ .data ; Data section db OxD ; ASCII Carriage Return OXOA ; ASCII Line Feed 0x00000002 dd Ox00000004 dd Ox00000008 Ox00000010 Ox03 ; shift value W_CHAR 'W' X_CHAR Y CHAR db Z_CHAR db 'z' N CHAR db EQUAL SIGN db '=' EQUAL_SIGN_LEN equ $ - EQUAL_SIGN ; Length of string HEX_IND db 'ox' HEX IND LEN equ $ - HEX IND ; Length of string MSG AO db 'W * Y = ! LEN AO equ $ - MSG AO ; Length of string MSG A1 db 'W N = '. LEN A1 equ $ - MSG A1 ; Length of string MSG BO db 'z / Y = ' ; Length of string 41 LEN_BO equ MSG_B1 db LEN_B1 equ RESULT dd VAR_STR_LEN $ - MSG_BO 'z >> N = " $ - MSG B1 Ox00000000 equ 4 Length of string 43 ; Length of string 44 ; Uninitialized Data section SECTION_HDR_ .bss VAR STR global VAR_STR resb VAR_STR_LEN 47 48 49 SECTION HDR .text global _START_ Code section ; Must be declared for using gcc ***************************************************************************** MACRO: Print_Result(MSG, LENGTH, RESULT) 54 PURPOSE: Sends a formatted string to STDOUT 55 INPUT: MSG [%1] :: Address of the string to print 56 ; LENGTH [%2] :: Length of the message (string) 57 RESULT [%3] :: Result (byte) -- to be converted to an ASCII string. 58 OUTPUT: NONE 59 ; USES: 60; NOTES: ***************************************************************************** %macro Print_Msg 3 ; Print message mov edi, %1 ; STRING [edi] :: Address of the string to print mov esi, %2 ; LENGTH [esi] :: Length of the string call _Our_Print 61 ; Print the HEXADECIMAL indicator (ex) mov edi, HEX IND ; STRING [edi] :: Address of the string to print mov esi, HEX_IND_LEN ; LENGTH [esi] :: Length of the string call _Our_Print ; Convert the given byte to a character-string mov edi, [%3] ; BYTE [edi] :: Byte to convert to string mov esi, VAR_STR ; STRING [esi] :: Address of the string mov edx, VAR_STR_LEN ; LENGTH [edx] :: Length of the string call _Byte_to_string ; Print the converted byte integer mov edi, VAR_STR ; STRING [edi] :: Address of the string to print mov esi, 2 ; LENGTH [esi] :: Length of the string call _Our_Print ; Print an ASCII newline (CR) control-character mov edi, CR ; STRING [edi] :: Address of the string to print mov esi, 1 ; LENGTH (esi] :: Length of the string call _Our_Print ; Print an ASCII newline (LF) control-character mov edi, LF ; STRING [edi] :: Address of the string to print mov esi, 1 ; LENGTH [esi] :: Length of the string call Our_Print 93 %endmacro 94 : 96 ; MACRO: Print_Var(VAR_STR, VAR_STR_LEN) 97 PURPOSE: Sends a formatted string to STDOUT 98 ; INPUT: VAR_STR [%1] :: Address of the string to print 99 ; VAR_STR_LEN [%2] :: Length of the message (string) 100 OUTPUT: NONE 101 USES: 102 NOTES: 193 ***************************************************************************** 104 - %macro CALL_Our_Print 2 ; Print the variable-name 106 mov edi, %1 ; STRING [edi] :: Address of the string to print 107 mov esi, %2 ; LENGTH (esi] :: Length of the string call _our_Print 109 %endmacro 110 105 108 111 . ************************************************************************************ 112 113 114 ; MACRO: Print Var(VAR STR, VAR STR LEN) PURPOSE: Sends a formatted string to STDOUT ; INPUT: VAR_STR %1] :: Address of the string to print BYTE [%2] :: Byte to convert to its ASCII equivalent 115 ; 116 ; OUTPUT: NONE 117 USES: 118 NOTES: 119 . ***************************************************************************** 120-%macro Print Var 2 121 ; Print the variable-name 122 mov edi, %1 ; STRING [edi] :: Address of the string to print 123 mov esi, 1 LENGTH [esi] :: Length of the string 124 call _our_Print 125 126 ; Print the EQUAL-SIGN 127 mov edi, EQUAL_SIGN ; STRING [edi] :: Address of the string to print 128 mov esi, EQUAL_SIGN_LEN ; LENGTH [esi] :: Length of the string 129 call _our_Print 130 131 ; Print the HEXADECIMAL indicator (ex) 132 mov edi, HEX_IND ; STRING [edi] :: Address of the string to print 133 mov esi, HEX_IND_LEN ; LENGTH [esi] :: Length of the string 134 call Our Print 135 136 ; Convert the given byte to a character-string mov edi, [%2] ; Address of BYTE [edi] :: Byte to convert to string 138 mov esi, VAR STR ; STRING [esi] :: Address of the string 139 mov edx, VAR_STR_LEN ; LENGTH [edx] :: Length of the string 140 call _Byte_to_String 141 142 ; Print the converted byte integer 143 mov edi, VAR_STR ; STRING [edi] :: Address of the string to print 144 mov esi, 2 ; LENGTH [esi] :: Length of the string 145 call Our Print 146 147 ; Print an ASCII carriage return (CR) control-character 148 mov edi, CR ; STRING [edi] :: Address of the string to print 149 mov esi, 1 ; LENGTH [esi] :: Length of the string 150 call _our_Print 151 137 155 152 ; Print an ASCII newline (LF) control-character 153 mov edi, LF ; STRING [edi] :: Address of the string to print 154 mov esi, 1 LENGTH [esi] :: Length of the string call Our_Print 156 %endmacro 157 158 - %macro Exit Program o 159 %ifdef WINDOWS 160 push 0 161 call _ExitProcess@4 162 %else 163 mov eax, 1 ; System call number (sys_exit) 164 int Ox80 ; Call kernel 165 %endif. 166 %endmacro 167 168 . ****************************************************************************** 169 ; MAIN: Demo 170 ; PURPOSE: Main entry-point to the EXECUTABLE. 171 NOTES: Equivalent to c language main(argc, argv) 172 . ****************************************************************************** 173 START_: ; Tell linker entry point 174 175 ;======== Display current values ======== 176 Display_variables: 177 - %ifdef DEBUG 178 ; Instructor Question 1: What are we doing here? 179 Print Var W CHAR, W 180 Print_Var X_CHAR, X 181 Print Var Y_CHAR, Y 182 Print_var Z_CHAR, Z 183 Print Var N CHAR, N. 184 CALL_Our_Print CR, 1 185 CALL_Our_Print LF, 1 186 %endif 187 188 ;======== calculate W * Y ======== 189 - Multiply WY: 205 190 mov eax, 0 ; Initialize eax prior to using it 191 mov ebx, 0 ; Initialize ebx prior to using it 192 mov esi, W ; Move the address of w into esi 193 mov eax, [esi] ; Move the value at w into eax 194 mov esi, Y ; Move the address of x into esi 195 mov ebx, [esi] ; Move the value at y into ebx 196 imul eax, ebx Multiply: X * Y 197 mov (RESULT), eax ; Store the result 198 199 - Display_WY_product: 200 Print_Msg MSG AO, LEN AO, RESULT 201 202 ;======== calculate X > Z ======== 234 - Shift_z_right_by_N: 235 mov eax, 0 ; Initialize ebx prior to using it 236 mov ecx, 0 ; Initialize ecx prior to using it 237 mov esi, Z ; Move the address of z into esi 238 mov eax, [esi] ; Move the value at z into eax mov esi, N ; Move the address of N into esi 240 mov ecx, esi] ; Move the value at N into ecx register 241 shr al, cl ; shift: N >> Z 242 mov (RESULT], eax ; Store the result, 243 244 - Display Z right shift: 245 Print Msg MSG_B1, LEN B1, RESULT 246 Instructor Question 2: Why is (Z / Y) equal to (N >> Z) ? 247 248 EXIT : 249 Exit_Program 250 251 END OF MAIN() 252 253 . ***************************************************************************** 254 ; PROC: Byte to String(BYTE, STRING, LENGTH) 255 ; PURPOSE: Convert byte integer into its ASCII (printable) equivalent. 256 ; INPUT: BYTE [edi] :: Byte to convert to string 257 ; STRING [esi] :: Address of the string 258 LENGTH edx] :: Length of the string 259 ; OUTPUT: eax :: Returns @ if successful, else -1. If successful, then the 260 ; Contents of the given string [ecx] contains the convert integer. 261 ; USES: eax :: Contains high/Low-order nibble of byte to convert 262 ; NOTES: 263 . *********************************************************************** * * * * * ; Start of procedure definition Save off the current contents of the regs 264 265 266 267 268 269 _Byte_to_String: push eax push ebx push ecx cmpedx, x3 jl Bad_B25 ; Make sure that given string is large enough ; It's not, so do not perform the operation 270 271 272 273 moveax, edi movecx, esi and eax, Ox000000F shr eax, 4. ; Byte to convert to string ; Get the address of the string buffer Mask off the high-order nibble ; Push the high-order nibble to the low-order nibble 274 275 276 277 278 279 280 281 282 283 284 285 ; Instructor Question 3: Why do we do this? add eax, 'o' mov [ecx], eax ; write the converted high-order nibble to the string add ecx, 1 ; Move the pointer to the next character position in the string ;Byte to convert to string Mask off the Low-order nibble moveax, edi and eax, Ox0000000F add eax, '0' mov ecx), eax add ecx, 1 ; write the converted low-order nibble to the string ; Move the pointer to the next character position in the string 286 287 ; Move a ZERO into eax letting the caller know that we were SUCCESSFUL ; Put a trailing zero in the string. ; We're done -- restore the registers used and return 288 moveax, O 289 mov [ecx], eax 290 jmp Done_B25 291 292 - Bad B2S: mov eax, -1 294 295 Done_B2S: 296 pop eax 297 pop ebx 298 pop ecx ; Move a ZERO into eax letting the caller know that we were unSUCCESSFUL ; Restore the previous contents of the regs 299 300 ret 301 ; End of procedure definition 302 303 . ***************************************************************************** 304 ; PROC: Our Print(STRING, LENGTH) 305 ; PURPOSE: Implements the system write call. 306 ; INPUT: STRING [edi] :: Address of the string to print 307 LENGTH [esi] :: Length of the string 308 ; OUTPUT: eax :: Returns o if successful, else -1. If successful, then the 309 Contents of the given string [ecx] contains the convert intege 310 ; USES: eax :: Contains high/Low-order nibble of byte to convert 311 NOTES: 312 : ***************************************************************************** 313 Our Print: ; Start of procedure definition 314 push eax ; Save off the current contents of the regs 315 push ebx 316 push ecx 317 push edx 318 319 %ifdef _WINDOWS 320 ; hstdout = GetstdHandle( STD_OUTPUT_HANDLE) 321 push -11 call _GetstdHandle@4 323 movebx, eax 324 325 ; WriteFile( hstdout, message, length(message), &bytes, 0); push 327 lea eax, [ebp-4] 328 push eax 329 push (message_end - message) 330 push message 331 ebx 332 call _WriteFile@20 333-%else 334 ; Instructor Question 4: What are we doing here? 335 mov eax, 4 ; System call number (sys_write) 336 mov ebx, 1 ; File descriptor (stdout) 337 mov ecx, edi Address of the message to write 338 mov edx, esi ; Message Length 322 326 os push 338 mov edx, esi ; Message Length 339 int Ox80 ; call the kernel 340 %endif 341 342 - Done_our_Print: 343 pop eax ; Restore the previous contents of the regs 344 pop ebx 345 pop ecx 346 pop edx 347 348 ; End of procedure definition ret codingground Compile and Execute Assembly Online (Nasm v2.13.01) SIMPLY EASY ODDING _exit Execute > Share main.asm STDIN 1 Bitwise operations: AND, OR, NOT, shifting (to multiply and divide) %ifdef _WINDOWS %xdefine SECTION HDR segment %xdefine _START__ __main main %xdefine EXIT extern GetstdHandle@4 extern WriteFile@20 extern _ExitProcess@4 %else %xdefine SECTION_HDR section %xdefine START__ _start %xdefine _EXIT_ _exit 13 %endif CR dd db X _SECTION_HDR_ .data ; Data section db OxD ; ASCII Carriage Return OXOA ; ASCII Line Feed 0x00000002 dd Ox00000004 dd Ox00000008 Ox00000010 Ox03 ; shift value W_CHAR 'W' X_CHAR Y CHAR db Z_CHAR db 'z' N CHAR db EQUAL SIGN db '=' EQUAL_SIGN_LEN equ $ - EQUAL_SIGN ; Length of string HEX_IND db 'ox' HEX IND LEN equ $ - HEX IND ; Length of string MSG AO db 'W * Y = ! LEN AO equ $ - MSG AO ; Length of string MSG A1 db 'W N = '. LEN A1 equ $ - MSG A1 ; Length of string MSG BO db 'z / Y = ' ; Length of string 41 LEN_BO equ MSG_B1 db LEN_B1 equ RESULT dd VAR_STR_LEN $ - MSG_BO 'z >> N = " $ - MSG B1 Ox00000000 equ 4 Length of string 43 ; Length of string 44 ; Uninitialized Data section SECTION_HDR_ .bss VAR STR global VAR_STR resb VAR_STR_LEN 47 48 49 SECTION HDR .text global _START_ Code section ; Must be declared for using gcc ***************************************************************************** MACRO: Print_Result(MSG, LENGTH, RESULT) 54 PURPOSE: Sends a formatted string to STDOUT 55 INPUT: MSG [%1] :: Address of the string to print 56 ; LENGTH [%2] :: Length of the message (string) 57 RESULT [%3] :: Result (byte) -- to be converted to an ASCII string. 58 OUTPUT: NONE 59 ; USES: 60; NOTES: ***************************************************************************** %macro Print_Msg 3 ; Print message mov edi, %1 ; STRING [edi] :: Address of the string to print mov esi, %2 ; LENGTH [esi] :: Length of the string call _Our_Print 61 ; Print the HEXADECIMAL indicator (ex) mov edi, HEX IND ; STRING [edi] :: Address of the string to print mov esi, HEX_IND_LEN ; LENGTH [esi] :: Length of the string call _Our_Print ; Convert the given byte to a character-string mov edi, [%3] ; BYTE [edi] :: Byte to convert to string mov esi, VAR_STR ; STRING [esi] :: Address of the string mov edx, VAR_STR_LEN ; LENGTH [edx] :: Length of the string call _Byte_to_string ; Print the converted byte integer mov edi, VAR_STR ; STRING [edi] :: Address of the string to print mov esi, 2 ; LENGTH [esi] :: Length of the string call _Our_Print ; Print an ASCII newline (CR) control-character mov edi, CR ; STRING [edi] :: Address of the string to print mov esi, 1 ; LENGTH (esi] :: Length of the string call _Our_Print ; Print an ASCII newline (LF) control-character mov edi, LF ; STRING [edi] :: Address of the string to print mov esi, 1 ; LENGTH [esi] :: Length of the string call Our_Print 93 %endmacro 94 : 96 ; MACRO: Print_Var(VAR_STR, VAR_STR_LEN) 97 PURPOSE: Sends a formatted string to STDOUT 98 ; INPUT: VAR_STR [%1] :: Address of the string to print 99 ; VAR_STR_LEN [%2] :: Length of the message (string) 100 OUTPUT: NONE 101 USES: 102 NOTES: 193 ***************************************************************************** 104 - %macro CALL_Our_Print 2 ; Print the variable-name 106 mov edi, %1 ; STRING [edi] :: Address of the string to print 107 mov esi, %2 ; LENGTH (esi] :: Length of the string call _our_Print 109 %endmacro 110 105 108 111 . ************************************************************************************ 112 113 114 ; MACRO: Print Var(VAR STR, VAR STR LEN) PURPOSE: Sends a formatted string to STDOUT ; INPUT: VAR_STR %1] :: Address of the string to print BYTE [%2] :: Byte to convert to its ASCII equivalent 115 ; 116 ; OUTPUT: NONE 117 USES: 118 NOTES: 119 . ***************************************************************************** 120-%macro Print Var 2 121 ; Print the variable-name 122 mov edi, %1 ; STRING [edi] :: Address of the string to print 123 mov esi, 1 LENGTH [esi] :: Length of the string 124 call _our_Print 125 126 ; Print the EQUAL-SIGN 127 mov edi, EQUAL_SIGN ; STRING [edi] :: Address of the string to print 128 mov esi, EQUAL_SIGN_LEN ; LENGTH [esi] :: Length of the string 129 call _our_Print 130 131 ; Print the HEXADECIMAL indicator (ex) 132 mov edi, HEX_IND ; STRING [edi] :: Address of the string to print 133 mov esi, HEX_IND_LEN ; LENGTH [esi] :: Length of the string 134 call Our Print 135 136 ; Convert the given byte to a character-string mov edi, [%2] ; Address of BYTE [edi] :: Byte to convert to string 138 mov esi, VAR STR ; STRING [esi] :: Address of the string 139 mov edx, VAR_STR_LEN ; LENGTH [edx] :: Length of the string 140 call _Byte_to_String 141 142 ; Print the converted byte integer 143 mov edi, VAR_STR ; STRING [edi] :: Address of the string to print 144 mov esi, 2 ; LENGTH [esi] :: Length of the string 145 call Our Print 146 147 ; Print an ASCII carriage return (CR) control-character 148 mov edi, CR ; STRING [edi] :: Address of the string to print 149 mov esi, 1 ; LENGTH [esi] :: Length of the string 150 call _our_Print 151 137 155 152 ; Print an ASCII newline (LF) control-character 153 mov edi, LF ; STRING [edi] :: Address of the string to print 154 mov esi, 1 LENGTH [esi] :: Length of the string call Our_Print 156 %endmacro 157 158 - %macro Exit Program o 159 %ifdef WINDOWS 160 push 0 161 call _ExitProcess@4 162 %else 163 mov eax, 1 ; System call number (sys_exit) 164 int Ox80 ; Call kernel 165 %endif. 166 %endmacro 167 168 . ****************************************************************************** 169 ; MAIN: Demo 170 ; PURPOSE: Main entry-point to the EXECUTABLE. 171 NOTES: Equivalent to c language main(argc, argv) 172 . ****************************************************************************** 173 START_: ; Tell linker entry point 174 175 ;======== Display current values ======== 176 Display_variables: 177 - %ifdef DEBUG 178 ; Instructor Question 1: What are we doing here? 179 Print Var W CHAR, W 180 Print_Var X_CHAR, X 181 Print Var Y_CHAR, Y 182 Print_var Z_CHAR, Z 183 Print Var N CHAR, N. 184 CALL_Our_Print CR, 1 185 CALL_Our_Print LF, 1 186 %endif 187 188 ;======== calculate W * Y ======== 189 - Multiply WY: 205 190 mov eax, 0 ; Initialize eax prior to using it 191 mov ebx, 0 ; Initialize ebx prior to using it 192 mov esi, W ; Move the address of w into esi 193 mov eax, [esi] ; Move the value at w into eax 194 mov esi, Y ; Move the address of x into esi 195 mov ebx, [esi] ; Move the value at y into ebx 196 imul eax, ebx Multiply: X * Y 197 mov (RESULT), eax ; Store the result 198 199 - Display_WY_product: 200 Print_Msg MSG AO, LEN AO, RESULT 201 202 ;======== calculate X > Z ======== 234 - Shift_z_right_by_N: 235 mov eax, 0 ; Initialize ebx prior to using it 236 mov ecx, 0 ; Initialize ecx prior to using it 237 mov esi, Z ; Move the address of z into esi 238 mov eax, [esi] ; Move the value at z into eax mov esi, N ; Move the address of N into esi 240 mov ecx, esi] ; Move the value at N into ecx register 241 shr al, cl ; shift: N >> Z 242 mov (RESULT], eax ; Store the result, 243 244 - Display Z right shift: 245 Print Msg MSG_B1, LEN B1, RESULT 246 Instructor Question 2: Why is (Z / Y) equal to (N >> Z) ? 247 248 EXIT : 249 Exit_Program 250 251 END OF MAIN() 252 253 . ***************************************************************************** 254 ; PROC: Byte to String(BYTE, STRING, LENGTH) 255 ; PURPOSE: Convert byte integer into its ASCII (printable) equivalent. 256 ; INPUT: BYTE [edi] :: Byte to convert to string 257 ; STRING [esi] :: Address of the string 258 LENGTH edx] :: Length of the string 259 ; OUTPUT: eax :: Returns @ if successful, else -1. If successful, then the 260 ; Contents of the given string [ecx] contains the convert integer. 261 ; USES: eax :: Contains high/Low-order nibble of byte to convert 262 ; NOTES: 263 . *********************************************************************** * * * * * ; Start of procedure definition Save off the current contents of the regs 264 265 266 267 268 269 _Byte_to_String: push eax push ebx push ecx cmpedx, x3 jl Bad_B25 ; Make sure that given string is large enough ; It's not, so do not perform the operation 270 271 272 273 moveax, edi movecx, esi and eax, Ox000000F shr eax, 4. ; Byte to convert to string ; Get the address of the string buffer Mask off the high-order nibble ; Push the high-order nibble to the low-order nibble 274 275 276 277 278 279 280 281 282 283 284 285 ; Instructor Question 3: Why do we do this? add eax, 'o' mov [ecx], eax ; write the converted high-order nibble to the string add ecx, 1 ; Move the pointer to the next character position in the string ;Byte to convert to string Mask off the Low-order nibble moveax, edi and eax, Ox0000000F add eax, '0' mov ecx), eax add ecx, 1 ; write the converted low-order nibble to the string ; Move the pointer to the next character position in the string 286 287 ; Move a ZERO into eax letting the caller know that we were SUCCESSFUL ; Put a trailing zero in the string. ; We're done -- restore the registers used and return 288 moveax, O 289 mov [ecx], eax 290 jmp Done_B25 291 292 - Bad B2S: mov eax, -1 294 295 Done_B2S: 296 pop eax 297 pop ebx 298 pop ecx ; Move a ZERO into eax letting the caller know that we were unSUCCESSFUL ; Restore the previous contents of the regs 299 300 ret 301 ; End of procedure definition 302 303 . ***************************************************************************** 304 ; PROC: Our Print(STRING, LENGTH) 305 ; PURPOSE: Implements the system write call. 306 ; INPUT: STRING [edi] :: Address of the string to print 307 LENGTH [esi] :: Length of the string 308 ; OUTPUT: eax :: Returns o if successful, else -1. If successful, then the 309 Contents of the given string [ecx] contains the convert intege 310 ; USES: eax :: Contains high/Low-order nibble of byte to convert 311 NOTES: 312 : ***************************************************************************** 313 Our Print: ; Start of procedure definition 314 push eax ; Save off the current contents of the regs 315 push ebx 316 push ecx 317 push edx 318 319 %ifdef _WINDOWS 320 ; hstdout = GetstdHandle( STD_OUTPUT_HANDLE) 321 push -11 call _GetstdHandle@4 323 movebx, eax 324 325 ; WriteFile( hstdout, message, length(message), &bytes, 0); push 327 lea eax, [ebp-4] 328 push eax 329 push (message_end - message) 330 push message 331 ebx 332 call _WriteFile@20 333-%else 334 ; Instructor Question 4: What are we doing here? 335 mov eax, 4 ; System call number (sys_write) 336 mov ebx, 1 ; File descriptor (stdout) 337 mov ecx, edi Address of the message to write 338 mov edx, esi ; Message Length 322 326 os push 338 mov edx, esi ; Message Length 339 int Ox80 ; call the kernel 340 %endif 341 342 - Done_our_Print: 343 pop eax ; Restore the previous contents of the regs 344 pop ebx 345 pop ecx 346 pop edx 347 348 ; End of procedure definition ret