# Assembly Language in UNIX ## Tools for ASM in UNIX ### Complier ```GCC``` 1. ```-m32```: x86 obj. code 2. ```-masm=intel```: Intel/AT&T syntax 3. ```-fno-stack-protecter```: disable stack protector, easier 4 understanding stack frame ### Assembler ```YASM``` > A computer program which translates assembly language to machine language 1. ```yasm -f elf32```: Output x86 object codes 2. ```yasm -f elf64```: Output x86_64 object codes ### Linker ```ld``` > A linker takes one or more object files generated by a compiler or an assembler and combines them into a single executable file, library file, or another 'object' file. 1. ```ld -m elf_i386```: Link with x86 object codes 2. ```ld -m elf_x86_64```: Link with x86_64 object codes ### Debugger ```gdb``` /w plugin ```gdb_peda``` 1. Installion: ```sh git clone https://github.com/longld/peda.git ~/peda echo "source ~/peda/peda.py" >> ~/.gdbinit ``` ## ASM Charcteristics 1. Low level language 2. One-to-one mapping from mnemonics to machine codes Assembler: Turn assembly codes to machine codes 3. Machine and platform-dependent ⋅⋅* Different machines/platforms have different assembler ⋅⋅* Even assemblers on the same machine/platform could be different ## Instruction Execution Cycle 1. **Fetch**: Read instruction code from address in PC and place in IR. ( IR ← Memory[PC] ) 2. **Decode**: Hardware determines what the opcode/function is. 3. **Fetch operands** (from memory if necessary): If any operands are memory addresses, known as the effective address, or EA for short, initiate memory read cycles to read them into CPU registers. 4. **Execute**: Perform the function of the instruction. If arithmetic or logic instruction, utilize the _ALU_ circuits to carry out the operation on data in registers. 5. **Store output** (in memory if necessary): If destination is a memory address, initiate a memory write cycle to transfer the result from the CPU to memory. ## Basic Execution Environment ### Addressable Memory 1. Long mode (x86_64) 1. Long mode allows the microprocessor to access 64-bit memory space, and access 64-bit long registers. 2. When a computer is powered on, the CPU starts in real mode and begins booting. The 64-bit operating system then checks and switches the CPU into Long mode and then starts new kernel-mode threads running 64-bit code. 3. 256 TB 4. 48-bit virtual address 2. Protected mode (x86) 1. Protected mode may only be entered after the system software sets up one descriptor table and enables the Protection Enable (PE) bit in the control register 0 (CR0) 2. 4GB 3. 32-bit virtual address 3. Real-address and Virtual-8086 modes 1. Real mode is characterized by a 20-bit segmented memory address space (giving exactly 1 MiB of addressable memory) and unlimited direct software access to all addressable memory, I/O addresses and peripheral hardware. 2. 1MB space 3. 20-bit address 4. 靠offset/segment定址 ### General Purpose Registers/Access Parts of Registers ![reg.](https://i.imgur.com/UeHJ2iE.png) ## Index and Base Registers 1. An index register is used for modifying operand addresses during the run of a program, typically for doing vector/array operations. 2. 同一暫存器,用到區塊不同,名稱即不同。 3. AH, AL, AX不會影響到整個RAX,若是EAX會,則會改變其他部分補0。 | 64-bit name | 32-bit name | 16-bit name | |-------------|-------------|-------------| | RDI | EDI | DI | | RSI | ESI | SI | | RBP | EBP | BP | | RSP | ESP | SP | ## Common Format ### Basic Element #### Integer Constants * Opt. leading +/- * Radix Characters: * h - hexadecimal * d - decimal * b - binary * r - encoded real (?) #### Interger Expressions * Operators and precedence levels: | Operator | Name | Precedence Level| |----------|-----------|-----------------| | () |parentheses|1| |+,-|unary plus,minus|2| |*,/|multiply,divide|3| |MOD|modulud|3| |+,-|add,substract|4| #### Character and String Constants * Enclose character in single or double quotes * 'A',"x" * ASCII character = **1byte** * Enclose strings in single or double quotes * "ABC",'xyx' * Each character occupies a single byte * Embedded quotes * 'Hello "World", Charles' #### Reserved Words & Identifiers * Reserved words cannot be used as identifiers * Identifiers * not case sensitive * first character must be a letter,_,@,?,or$ #### Directives(組合程式指引) * Commands that are recognized and acted upon by the assembler * Not part of the Intel instruction set * Used to declare code * Different assemblers have different directives #### Instructions * Assembled into machine code by assembler * Executed at runtime by the CPU * An Instruction contains: * Label (opt.) * Mnemonic (man.) * Operands (dep. on the instruction) * Commands (opt.) #### Labels * Act as place markers * Data label * unique * myArray (not folloewd by colon) * Code label * target of jump and loop instructions * L1: (folloewd by colon)) #### Mnemonics and Operands * Instruction Mnemonics * memory aid MOV,ADD,SUB.... * Operands * constant * constant expression * register * memory(datalabel) #### Instruction Format Examples ```nasm ;No operands stc ;set Carry flag ;One operand inc eax ;register inc BYTE PTA [a] ;memory ;Two operands add ebx,ecx ;ebx = ebx + ecx sub BYTE[a],25 ;a=a-25 add eax, 36*25 ;eax = eax + 36*25 ``` ## The Assemble-Link-Execute Cycle ![Assemble-Link-Execute cycle.](https://i.imgur.com/JzVovWs.png) 1. Create an ASCII text file (source file). 2. The assembler reads the source file and produces an object file. 3. The linker reads the object file and checks to see if the program contains any calls to procedures in a link library. 4. The operating system loader utility reads the executable file into memory and branches the CPU to the program’s starting address, and the program begins to execute. ## Defining Data ### Intrinsic Data Types(內建資料型別) | Type | Usage | |-------------|-------------------------------------------| | BYTE | 8-bit unsigned integer. B stands for byte| | SBYTE | 8-bit signed integer. S stands for signed| | WORD | 16-bit unsigned integer| |SWORD|16-bit signed integer| |DWORD|32-bit unsigned integer. D stands for double| |SDWORD|32-bit signed integer. SD stands for signed double| |FWORD|48-bit integer (Far pointer in protected mode)| |QWORD|64-bit integer. Q stands for quad| |TBYTE|80-bit (10-byte) integer. T stands for Ten-byte| |REAL4|32-bit (4-byte) IEEE short real| |REAL8|64-bit (8-byte) IEEE long real| |REAL10|80-bit (10-byte) IEEE extended real| ### Data definition statement 1. A data definition statement sets aside storage in memory for a variable. 2. All initializers become binary data in memory 3. A data definition has the following syntax: ```nasm [name] directive initializer [,initializer]... count DWORD 12345 ``` 4. Legacy Data Directives: |Directive|Usage| |-|-| |DB|8-bit integer| |DW|16-bit integer| |DD|32-bit integer or real| |DQ|64-bit integer or real| |DT|define 80-bit (10-byte) integer| ### Defining BYTE and SBYTE Data 1. Each of the following defines a single byte of storage ```nasm value1 BYTE 'A' ; character literal value2 BYTE 0 ; smallest unsigned byte value3 BYTE 255 ; largest unsigned byte value4 SBYTE −128 ; smallest signed byte value5 SBYTE +127 ; largest signed byte ``` 2. A question mark (?) initializer leaves the variable uninitialized. ```nasm value6 BYTE ? ``` 3. Multiple Initializers ```nasm list BYTE 10,20,30,40 ``` * Memory layout of a byte sequence. ![Memory layout of a byte sequence](https://i.imgur.com/x44N7jR.png) 4. Defining Strings * A string is implemented as an array of characters * usually enclosed in quotation marks * often will be _null-terminated_ (ends with a null byte ,containing 0.) * Example ```nasm greeting1 BYTE "Good afternoon",0 greeting2 BYTE 'Good night',0 greeting1 BYTE 'G','o','o','d'....etc. ;can be divided between multiple lines greeting1 BYTE "Welcome to the Encryption Demo program " BYTE "created by Kip Irvine.",0dh,0ah BYTE "If you wish to modify this program, please " BYTE "send me a copy.",0dh,0ah,0 ``` * End-of-line character sequence: * 0Dh = carriage return * 0Ah = line feed 5. DUP Operator 1. Use DUP to allocate (create space for) an array or string. Syntax: counter DUP ( argument ) ```nasm var1 BYTE 20 DUP(0) ; 20 bytes, all equal to zero var2 BYTE 20 DUP(?) ; 20 bytes, uninitialized var3 BYTE 4 DUP("STACK") ; 20 bytes: "STACKSTACKSTACKSTACK" var4 BYTE 10,3 DUP(0),20 ; 5 bytes ``` ### Defining WORD and SWORD Data 1. Define storage for 16-bit integers 1. or double characters 2. single value or multiple values ```nasm word1 WORD 65535 ; largest unsigned value word2 SWORD –32768 ; smallest signed value word3 WORD ? ; uninitialized, unsigned word4 WORD "AB" ; double characters myList WORD 1,2,3,4,5 ; array of words array WORD 5 DUP(?) ; uninitialized array ``` 3. Memory layout ![Memory layout, 16-bit word array.](https://i.imgur.com/XCMLRSM.png) ### Defining DWORD and SDWORD Data 1. Storage definitions for signed and unsigned 32-bit integers ```nasm val1 DWORD 12345678h ; unsigned val2 SDWORD −2147483648 ; signed val3 DWORD 20 DUP(?) ; unsigned array ;DD directive can also be used to define doubleword data val1 DD 12345678h ; unsigned val2 DD −2147483648 ; signed ;The DWORD can be used to declare a variable that contains the 32-bit offset of another variable. pVal DWORD val3 ;Array of 32-bit myList DWORD 1,2,3,4,5 ``` ### Defining QWORD, TBYTE, Real Data 1. Storage definitions for quadwords, tenbyte values, and real numbers ```nasm ;storage for 64-bit (8-byte) values quad1 QWORD 1234567812345678h ;DQ quad1 DQ 1234567812345678h ``` ### Uninitialized Data (BSS Section) * resb – 1-byte * resw – 2-byte * resd – 4-byte * resq – 8-byte * rest – 10-byte * resdq – 16-byte * reso – the same as resdq ```nasm buffer: resb 64 ; reserve 64 bytes wordvar: resw 1 ; reserve a word realarray resq 10 ; array of ten reals ``` ## Symbolic Constants > A symbolic constant (or symbol definition) is created by associating an identifier (a symbol) with an integer expression or some text. Symbols do not reserve storage. They are used only by the assembler when scanning a program, and they cannot change at runtime. The following table summarizes their differences. ![ver.](https://i.imgur.com/biiMZ1Q.png) ### Equal-Sign Directive 1. name = expression 1. 32-bit integer value. 2. redefined 3. name is called a symbolic constant ```nasm COUNT = 500 mov eax, COUNT ``` ### Calculating the Sizes of Arrays and Strings * current location counter: $ ```nasm list BYTE 10,20,30,40 ListSize = 4 ;Divide total number of bytes by 2 (the size of a word) list WORD 1000h,2000h,3000h,4000h ListSize = ($ - list) / 2 ;Divide total number of bytes by 4 (the size of a doubleword) list DWORD 1,2,3,4 ListSize = ($ - list) / 4 ``` ### EQU Directive * Define a symbol as either an integer or text expression. * Cannot be redefined ```nasm PI EQU <3.1416> pressKey EQU <"Press any key to continue...",0> .data prompt BYTE pressKey ``` ### TEXTEQU Directive * Define a symbol as either an integer or text expression * Called a **text macro** * Can be redefined ```nasm name TEXTEQU <text> name TEXTEQU textmacro name TEXTEQU %constExpr continueMsg TEXTEQU <"Do you wish to continue (Y/N)?"> rowSize = 5 .data prompt1 BYTE continueMsg count TEXTEQU %(rowSize * 2) ; evaluates the expression setupAL TEXTEQU <mov al,count> .code setupAL ; generates: "mov al,10" ``` ## Data Transfers Instructions ### Operand Types * Immediate—uses a numeric literal expression * Register—uses a named register in the CPU * Memory—references a memory location * Instruction Operand Notation, 32-Bit Mode. |Operand|Description| |-|-| |reg8| 8-bit general-purpose register: AH, AL, BH, BL, CH, CL, DH, DL| |reg16| 16-bit general-purpose register: AX, BX, CX, DX, SI, DI, SP, BP| |reg32| 32-bit general-purpose register: EAX, EBX, ECX, EDX, ESI, EDI, ESP, EBP| |reg Any| general-purpose register| |sreg| 16-bit segment register: CS, DS, SS, ES, FS, GS| |imm| 8-, 16-, or 32-bit immediate value| |imm8| 8-bit immediate byte value| |imm16| 16-bit immediate word value| imm32| 32-bit immediate doubleword value| |reg/mem8| 8-bit operand, which can be an 8-bit general register or memory byte| |reg/mem16| 16-bit operand, which can be a 16-bit general register or memory word| |reg/mem32| 32-bit operand, which can be a 32-bit general register or memory doubleword| |mem| An 8-, 16-, or 32-bit memory operand| ```nasm [label:] mnemonic [operands] [ ; comment ] mnemonic mnemonic [destination] mnemonic [destination], [source] mnemonic destination], [source-1],[source-2] ``` ### Direct Memory Operands * A direct memory operand is a named reference to storage in memory. * The named reference (label) is automatically dereferenced by the assembler ```nasm .data var1 BYTE 10h .code mov al,var1 ; AL = 10h mov al,[var1] ; AL = 10h ``` ### MOV Instruction * Syntax: ```nasm MOV destination,source ``` * Both operands must be the same size. * Both operands cannot be memory operands. * The instruction pointer register (IP, EIP, or RIP) cannot be a destination operand. ```nasm MOV reg,reg MOV mem,reg MOV reg,mem MOV mem,imm MOV reg,imm mov eax, [ebx + ecx*4 + 4] mov [0x600004], ebx inc [0x600008] ; this is invalid inc DWORD PTR [0x600008] mov [0x600000], [0x600004] ; this is invalid ``` ### XCHG Instruction * XCHG exchanges the values of two operands. At least one operand must be a register. No immediate operands are permitted. ```nasm .data var1 WORD 1000h var2 WORD 2000h .code xchg ax,bx ; exchange 16-bit regs xchg ah,al ; exchange 8-bit regs xchg var1,bx ; exchange mem, reg xchg eax,ebx ; exchange 32-bit regs xchg var1,var2 ; error: two memory operands ``` ### Direct-Offset Operands * A constant offset is added to a data label to produce an effective address (EA). The address is dereferenced to get the value inside its memory location. ```nasm .data arrayB BYTE 10h,20h,30h,40h .code mov al,arrayB+1 ; AL = 20h mov al,[arrayB+1] ; alternative notation ``` ### LEA Instruction * Move the address into the target operand ```nasm lea eax, [0x600000] ; eax = 0x600000 lea eax, [0x600000+4] ; eax = 0x600000 + 4 lea eax, [ebx + 17] ; eax = ebx + 17 lea eax, [ebx + ecx*4 + 4] ; eax = ebx + ecx*4 + 4 ``` * Some special usage * Add a constant to a register * Quick multiplication of 2, 3, 5, 9 ## Bitwise Operations |Operation| Description| |-|-| |AND| Boolean AND operation between a source operand and a destination operand.| |OR| Boolean OR operation between a source operand and a destination operand.| |XOR| Boolean exclusive-OR operation between a source operand and a destination operand.| |NOT| Boolean NOT operation on a destination operand.TEST Implied boolean AND operation between a source and destination operand, setting the CPU flags appropriately.| ## Shift and Rotate Instructions * Shift and Rotate Instructions. ![Shift and Rotate Instructions.](https://i.imgur.com/ptyXxDi.png) ### Shift Instruction > Shift left evalue = value * 2 > Shift right evalue = value / 2 #### Logical shift * SHL ![SHL](https://i.imgur.com/Opmu9Jj.png) * SHR ![SHR](https://i.imgur.com/4d1Y3ZU.png) ```nasm SHL reg,imm8 SHL mem,imm8 SHL reg,CL SHL mem,CL ``` #### Arithmetic shift right * SAL == SHL * SAR reg/mem, imm8/cl ![SAR](https://i.imgur.com/BQJaCN3.png) ### Rotate Instructions #### Rotate w/o the carry flag * ROL reg/mem, imm8/cl * ROR reg/mem, imm8/cl ![rolror](https://i.imgur.com/VPPU1FQ.png) #### Rotate with the carry flag * RCL reg/mem, imm8/cl * RCR reg/mem, imm8/cl ![RCLRCR](https://i.imgur.com/KuAsKe0.png) ## Multiplication and Division Instructions ### MUL Instruction * In 32-bit mode, MUL (unsigned multiply) instruction multiplies an 8-, 16-, or 32-bit operand by either AL, AX, or EAX. ```nasm MUL r/m8 MUL r/m16 MUL r/m32 ``` |Multiplicand| Multiplier| Product| |-|-|-| |AL| reg/mem8| AX| |AX| reg/mem16| DX:AX| |EAX| reg/mem32| EDX:EAX| ### IMUL Instruction * IMUL (signed integer multiply ) multiplies an 8-, 16-, or 32-bit signed operand by either AL, AX, or EAX ```nasm IMUL reg/mem8 ; AX = AL * reg/mem8 IMUL reg/mem16 ; DX:AX = AX * reg/mem16 IMUL reg/mem32 ; EDX:EAX = EAX * reg/mem32 ``` ### DIV Instruction * The DIV (unsigned divide) instruction performs 8-bit, 16-bit, and 32-bit division on unsigned integers |Dividend| Divisor| Quotient| Remainder| |-|-|-|-| |AX| reg/mem8| AL| AH| |DX:AX| reg/mem16| AX| DX| |EDX:EAX| reg/mem32| EAX| EDX| * 32-bit example ```nasm mov dx,0 ; clear dividend, high mov ax,8003h ; dividend, low mov cx,100h ; divisor div cx ; AX = 0080h, DX = 0003h ``` ![illu](https://i.imgur.com/4vH2DzZ.png) ### Sign Extension Instructions (CBW, CWD, CDQ) * CBW (convert byte to word) extends AL into AH ![CBW](https://i.imgur.com/Whe3S4f.png) * CWD (convert word to doubleword) extends AX into DX * CDQ (convert doubleword to quadword) extends EAX into EDX ### IDIV Instruction * IDIV (signed divide) performs signed integer division * Same syntax and operands as DIV instruction ```nasm mov eax,-48 cdq ; extend EAX into EDX mov ebx,5 idiv ebx ; EAX = -9, EDX = -3 ``` ## Control Flow Instructions ### TEST Instruction * Performs a nondestructive AND operation between each pair of matching bits in two operands * No operands are modified, but the Zero flag is affected. * Example: jump to a label if either bit 0 or bit 1 in AL is set. ```nasm test al,00000011b jnz ValueFound ``` ### CMP Instruction * Compares the destination operand to the source operand * Nondestructive subtraction of source from destination (destination operand is not changed) * Syntax: ```CMP destination, source``` ```nasm mov ax,5 cmp ax,10 ; ZF = 0 and CF = 1 ``` #### Conditional Jumps * can be divided into four groups * Jumps based on specific flag values * Jumps based on equality between operands or the value of (E)CX * Jumps based on comparisons of unsigned operands * Jumps based on comparisons of signed operands * Jumps Based on Specific Flag Values ![Jumps Based on Specific Flag Values](https://i.imgur.com/uIVCnzu.png) * Jumps Based on Equality ![Jumps Based on Equality](https://i.imgur.com/AYxCVAx.png) * Jumps Based on Unsigned Comparisons ![Jumps Based on Unsigned Comparisons](https://i.imgur.com/0QxM34x.png) * Jumps Based on Signed Comparisons ![Jumps Based on Signed Comparisons](https://i.imgur.com/FOfVGGA.png) #### Conditional Structures ![Conditional Structures](https://i.imgur.com/YguYuGR.png) ![Conditional Structures2](https://i.imgur.com/FDcycv6.png) #### Implement Compound ##### Logical AND Operator * When implementing the logical AND operator, consider that HLLs use short-circuit evaluation * ```if (al > bl) AND (bl > cl) X = 1``` ```nasm cmp al,bl ; first expression... ja L1 jmp next L1: cmp bl,cl ; second expression... ja L2 jmp next L2: mov X,1 ; both true: set X to 1 next: ``` * reduce the code to five instructions by changing the initial JA instruction to JBE: ```nasm cmp al,bl ; first expression... jbe next ; quit if false cmp bl,cl ; second expression jbe next ; quit if false mov X,1 ; both are true next: ``` ##### Logical OR Operator * When implementing the logical OR operator, consider that HLLs use short-circuit evaluation * We can use "fall-through" logic to keep the code as short as possible: * ```if (al > bl) OR (bl > cl) X = 1``` ```nasm cmp al,bl ; 1: compare AL to BL ja L1 ; if true, skip second expression cmp bl,cl ; 2: compare BL to CL jbe next ; false: skip next statement L1: mov X,1 ; true: set X = 1 next: ``` ### WHILE Loops * A WHILE loop is really an IF statement followed by the body of the loop, followed by an unconditional jump to the top of the loop. ```nasm L1: cmp or test J<INV>cond L2 ; do something here jmp L1 L2: ``` ```while( eax < ebx) eax = eax + 1;``` ```nasm mov eax,val1 ; copy variable to EAX beginwhile: cmp eax,val2 ; if not (val1 < val2) jnl endwhile ; exit the loop inc eax ; val1++; dec val2 ; val2--; jmp beginwhile ; repeat the loop endwhile: mov val1,eax ; save new value for val1 ``` ### FOR Loop * CPU built-in loops * Use CX/ECX/RCX as the counter * Repeat the loop for 10 times ```nasm mov ecx, 10 L1: ; do something here loop L1 ``` * C-style FOR loop * ```for (i = 0; i < 10; i++) { /* … */ }``` ```nasm mov DWORD [i], 0 L1: cmp DWORD [i], 10 jge L2 ; do something here inc DWORD [i] jmp L1 L2: ``` ## Stack Operations * Imagine a stack of plates * plates are only added to the top * plates are only removed from the top * LIFO structure ![a stack of plates](https://i.imgur.com/U6Y216W.png) ### Runtime Stack * Managed by the CPU, using two registers * SS (stack segment) * ESP (stack pointer)(SP in Real-address mode) ![A stack containing a single value](https://i.imgur.com/7p6cyJs.png) ### PUSH Operation > Put a number into the stack > ESP = ESP - sizeof(object) > [ESP] = object * A 32-bit push operation decrements the stack pointer by 4 and copies a value into the location pointed to by the stack pointer. ![Pushing integers on the stack](https://i.imgur.com/yeQfWRl.png) * Same stack after pushing two more integers: ![Stack, after pushing 00000001 and 00000002.](https://i.imgur.com/jG6Qdsu.png) * The stack grows downward. The area below ESP is always available (unless the stack has overflowed).**higher->bottom** * Syntax ```nasm PUSH reg/mem16 PUSH reg/mem32 PUSH imm32 ``` ### POP Operation > Remove a number from the stack > ESP = ESP + sizeof(top object) * Copies value at stack[ESP] into a register or variable. * Adds n to ESP, where n is either 2 or 4. * value of n depends on the attribute of the operand receiving the data ![Popping a value from the runtime stack.](https://i.imgur.com/15Cn4C9.png) > pop edx => edx=[esp] > pop dword ptr[a] =>[a]=[esp] > POP只是esp值的改變,除非有重新push蓋掉本來的位置 * Syntax ```nasm POP reg/mem16 POP reg/mem32 ``` ## Function Calls * The CALL instruction calls a procedure * pushes offset of next instruction on the stack * copies the address of the called procedure into EIP * The RET instruction returns from a procedure * pops top of stack into EIP ### Call and Return Example * CALL: change program control flow * Call a function * PUSH return address into the stack * Set RIP to be the entry point of the target * function * Parameters can be passed by using registers or the stack * RET: return to the caller * pop rip * ...but you cannot do this by yourself – dst cannot be RIP/EIP * Return value is passed by using RAX/EAX register ```nasm main PROC 00000020 call MySub 00000025 mov eax,ebx . . main ENDP MySub PROC 00000040 mov eax,edx . . ret MySub ENDP ``` * The CALL instruction pushes 00000025 onto the stack, and loads 00000040 into EIP ![Executing a CALL instruction](https://i.imgur.com/HQ21w2e.png) * The RET instruction pops 00000025 from the stack into EIP ![Executing the RET instruction](https://i.imgur.com/xIGiggE.png) ### Nested Procedure Calls ![Nested Procedure Calls](https://i.imgur.com/FePYfpU.png) ### Passing Register Arguments to Procedures 1. Use registers 1. Easier and faster 2. Limited number of stacks ==> Limited number of parameters 2. Use stack 1. ◦ Basically no limitation on the number of parameters (only depends on the available stack space) ```nasm .data theSum DWORD ? .code main PROC mov eax,10000h ; argument mov ebx,20000h ; argument mov ecx,30000h ; argument call Sumof ; EAX = (EAX + EBX + ECX) mov theSum,eax ; save the sum ``` > After the CALL statement, we have the option of copying the sum in EAX to a variable. :::info Feel free to contact me cyc@charleschang.io ::: ###### tags: `ASM` `Reverse`