287x Filetype PDF File size 0.32 MB Source: static1.squarespace.com
Assembly language for x86 processors Assembly language for x86 processors 8th edition. Assembly language for x86 processors 7th edition programming exercises solutions. Assembly language for x86 processors 8th pdf. Assembly language for x86 processors solution manual. Assembly language for x86 processors solutions. Assembly language for x86 processors by kip irvine. Assembly language for x86 processors answers. Assembly language for x86 processors 7th edition. Student resources for this book (pearsonhighered.com) Getting Started with MASM and Visual Studio 2022 Chapter Objectives Getting Started with MASM and Visual Studio 2019 Buy at Vitalsource.com Debugging Tools Watch Sample Tutorial Videos Instructor Resources Additional Workbooks Articles Assembler Language More ? Advanced embedding information, examples and help! Backwards Compatible Assembly Language Family For a list of specific x86 assembly language instructions, see x86 instruction lists. Additional citations are required to verify this article. Help improve this article by citing authoritative sources. Unlisted material may be challenged and removed. Find Sources: "X86 Assembly Language" News Newspapers Books Scholars JSTOR (March 2020) (Learn how and when to remove this news template) x86 assembly language is the name of a family of assembly languages that provide some level of backward compatibility with processors. dating back to the Intel 8008 microprocessor introduced in April 1972. It is used to create object code for x86 class processors. Considered a programming language, assembler is machine-specific and low-level. Like all assembly languages, x86 assembly uses mnemonics to represent basic CPU or machine code instructions. Assembly languages are most commonly used in detailed and time-sensitive applications such as small real-time embedded systems, operating system kernels, and device drivers, but can also be used in other applications. The compiler sometimes generates assembly code as an intermediate step in converting a high-level program into machine code. Keywords x86 assembly language reserved keywords[4][5] lds les lfs lgs lss pop push ins outs lahf sahf popf pushf cmc clc stc cli sti cld std add adc sub sbb cmp inc dec test sal shl neg sar shrd shr not s bond un or xor imul mul div idiv cbtw cwtl cwtd cltd daa das aaa aas aamwait fwait movs cmps stos lods scas xlat rep repnz repz lcall call ret lret enter exit jcxz loop loopnz loopz jmp ljmp int into iret sldt str lldt ltr verr verw sgdt sidt lgdt lidtsplbscl bl fddiv fddiv fddiv fdcw fldenv fprem fucom movwz pushcomcom rcr rol ror setcc bswap xadd xchg wbinvd invd invlpg lock nop hltsubrpdfil fst fst fscale fprem frndint fxtract fabs fchs fcom fcomp fcompp ficom ficomp ftst fxam fptan fpatan f2xm1 fyl2x fyl2xp1 fldl2e fldl2t fldlg2 fldln2 fldpi fldz finit fnint fnop fstew fsave fnsave fnstew fnstenv fstsw fnstsw frstor fwait wait fclex fnclex fdecstp ffree fincstp Mnemonics and Opcodes More Information: x86 Instruction Lists Each x86 assembly instruction is represented by a mnemonic, often combined with one or more operands converted to one or more bytes called an opcode; for example, the NOP instruction is converted to 0x90 and the HLT instruction is converted to 0xF4.[3] There are potential opcodes without documented mnemonics that can be interpreted differently by different processors, causing a program using them to behave inconsistently or even throw an exception on some processors. These opcodes often appear in coding competitions to make the code smaller, faster, and more elegant, or simply to showcase the author's skills. The x86 assembler syntax has two main syntax branches: Intel syntax and AT&T syntax.[6] Intel syntax has dominated the DOS and Windows world, and AT&T syntax has dominated the Unix world ever since Unix was developed at AT&T Bell Labs.[7] Here is a summary of the main differences between Intel syntax and AT&T syntax: Intel AT&T orders the source before the destination. movl $5, %eax destination before source. mov eax, mnemonics with 5 parameterswhere the letter indicates the size of the operands: q for qword, l for long (dword), w for word, and b for byte. addl $4, %esp Derived from the name of the register used (e.g. rax, eax, ax, al for q, l, w or b, respectively). add esp, 4 sigils immediately preceding "$", registers preceding "%".[6] Assembler automatically recognizes the type of symbols; i.e. whether they are registers, constants or something else. Effective addresses General syntax DISP(BASE,INDEX,SCALE). Example: movl offset(%ebx,%ecx,4), %eax Arithmetic expressions in square brackets; additionally, use size keywords such as byte, word, or iwd if the size cannot be determined from the operands. Example: mov eax, [ebx + ecx*4 + offset] Many x86 assemblers use Intel's syntax, including FASM, MASM, NASM, TASM, and YASM. GAS, which originally used the AT&T syntax, supports both syntaxes since version 2.10 via the .intel_syntax directive. The peculiarity of the AT&T x86 syntax is that the x87 operands are inverted, which is an inherited error from the original AT&T assembly language. The AT&T syntax is almost universal for all other architectures with the same traffic order; This was the original syntax of the PDP-11 kit. The Intel syntax is specific to the x86 architecture and is used in the x86 platform documentation. Registers For more information: X86 architecture x86 registers x86 processors have a set of registers that can be used to store binary data. Collectively, the data and address registers are referred to as general registers. Each register has a special purpose in addition to what each can do: [3] AX multiplies/divides, loads a string and holds index registers BX for counting MOVE CX for string operations and shifts the DX port address for IN and OUT SP points the stack up BP points to the base of the stack frame SI points to the source in stream operations DI points to the destination in stream operations Together with the general registers there are: Pointer IP instruction FLAGS segment registers (CS, DS, ES, FS, GS, SS) which define where the 64k segment starts (no FS and GS on 80286 and older), other extension registers (MMX, 3DNow!, SSE, etc. ). ) (Pentium and higher only). The IP register indicates the memory offset of the next instruction in the code segment (points to the first byte of the instruction). The programmer does not have direct access to the IP registry. x86 registers can be used using the MOV instruction. For example, in the Intel syntax: mov ax, 1234h ; copies value 1234hex (4660d) into AX register mov bx, ax ; copies the value of the AX register into the BX register Segmented Addressing The 8086's real- and virtual-mode x86 architecture uses a process known as segmentation to address memory, rather than the flat memory model used in many other environments. Segmentation consists of dividing a memory address into two parts, a segment and an offset; the segment indicates the start of a group of 64 KB (64 × 210) addresses, and the offset determines how far from this start address the requested address is. Segmented addressing requires two registers for a full memory address. One to hold the segment, the other to hold the offset. To convert back to a single address, the segment value is shifted four bits to the left (equivalent to multiplying by 24 or 16) and then added to the offset to form the full address, thus breaking the 64k barrier. a smart choice of address, although it makes programming much more complicated. For example, in real/protected-only mode, if DS contains the hexadecimal number 0xDEAD and DX contains the number 0xCAFE, they together point to the memory address 0xDEAD * 0x10 + 0xCAFE = 0xEB5CE. Therefore, the processor can address up to 1,048,576 bytes (1 MB) in real mode. By combining the segment and offset values, we find a 20-bit address. The original IBM PC limited programs to 640 KB, but the extended memory specification was used to implement ita switching scheme that was discontinued when newer operating systems such as Windows used the larger address ranges of newer processors and introduced custom virtual memory schemes. Protected mode was used by OS/2 starting with the Intel 80286. Several disadvantages, such as B. the inability to access the BIOS and the inability to return to real mode without resetting the processor prevented widespread use. The 80286 was still limited to addressing memory in 16-bit segments, meaning only 216 bytes (64 KB) could be accessed at a time. To access the enhanced functionality of the 80286, the operating system places the processor in protected mode, which provides 24-bit addressing and thus 224 bytes of memory (16 megabytes). In protected mode, the segment selector can be divided into three parts: a 13-bit index, a table pointer bit that determines whether the entry is a GDT or LDT, and a 2-bit desired permission level; see x86 memory segmentation. When referencing an address with a segment and an offset, the notation segment:offset is used, so in the above example the flat address 0xEB5CE can be written as 0xDEAD:0xCAFE or as a segment and offset register pair; DS: DX. There are several special combinations of segment registers and general registers that point to important addresses: CS:IP (CS is the code segment, IP is the instruction pointer) points to the address where the processor reads the next byte of code. SS:SP (SS is the stack segment, SP is the stack pointer) points to the address of the top of the stack, i. H. the last shifted byte. DS:SI (DS is the data segment, SI is the source index) is often used to specify the string data to be copied to ES:DI. ES:DI (ES is the extra segment, DI is the target index) is usually used to point to the string copy target as mentioned above. The Intel 80386 had three modes of operation: real mode, protected mode, and virtual mode. A protected mode that debuted in 80286expanded to allow the 80386 to address up to 4 GB of memory, the brand new 8086 Virtual Mode (VM86) allowed one or more real mode programs to run in a protected environment that accurately emulated real mode, although some programs were incompatible. (usually as a result of memory addressing tricks or unspecified opcodes). The 80386 with 32-bit flat memory in Enhanced Protected Mode was arguably the most important feature change in the x86 family of processors until AMD released the x86-64 in 2003 as it spurred widespread adoption of Windows 3.1 (which was based on Protected Mode) . ), because Windows can now run multiple applications simultaneously, including DOS applications, taking advantage of virtual memory and convenient multitasking. Execution modes More information: X86 architecture X86 processors support five modes of x86 code execution: real mode, protected mode, long mode, virtual 86 mode, and system control mode where some instructions are available and others are not. A subset of the 16-bit instructions are available on 16-bit x86 processors such as the 8086, 8088, 80186, 80188, and 80286. These instructions are available in real mode on all x86 processors and in 16-bit protected mode. (80286 and later) there are additional instructions for Protected Mode. In 80386 and later 32-bit instructions (including later extensions), they are also available in all modes, including real mode; these processors added V86 mode and 32-bit protected mode, and these modes provide additional instructions to control their functionality. SMM is available with special instructions for some Intel i386SL, i486 and later processors. Finally, 64-bit instructions and other registers are also available in long mode (AMD Opteron and later). The instruction set is the same in all modes, but the memory addressing and word size are different, requiring different programming strategies. Modes in which x86 code can execute: Real mode (16-bit) 20-bit segmentedAddress space (meaning only 1MB of memory can be addressed - a little more actually), direct software access to peripherals, and no concept of memory protection or multitasking at the hardware level. Computers using the BIOS boot in this mode. Protected Mode (16-bit and 32-bit) Extends physical addressable memory up to 16MB and virtual addressable memory up to 1GB. Provides permissions and protected memory to prevent programs from harming each other. 16-bit protected mode (used at the end of the DOS era) used a complex multi-segment memory model. 32-bit protected mode uses a simple flat memory model. Long Mode (64-bit) Primarily an extension of the 32-bit instruction set (protected mode), but unlike the transition from 16-bit to 32-bit, many instructions have been removed in 64-bit mode. AMD Pioneer. 8086 Virtual Mode (16-bit) A special hybrid mode of operation that allows programs and real mode operating systems to run under the Protected Mode Manager operating system. System Management Mode (16-bit) Handles system-wide functions such as power management, system hardware, and custom code developed by the OEM. It is intended for use by system firmware only. All normal execution, including the operating system, is suspended. An alternative software system (usually found in the computer's firmware or in a hardware-assisted debugger) is then run with elevated privileges. Switching Modes The processor runs in real mode immediately after power up, so the operating system kernel or other program must explicitly switch modes if it wants to work in non-real mode. Mode switching is done by modifying certain bits of the processor's control registers after some preparation, and some additional modifications may be required after the switch. Examples On a computer with an old BIOS, the BIOS and bootloader run in real mode, then the 64-bit OS kernel checks and switchesThe CPU enters long mode and then starts new kernel-mode threads with 64- bit code. On a UEFI computer, the UEFI firmware (except for CSM and older option ROMs), the UEFI boot loader, and the UEFI operating system kernel run in long mode. Instruction Types In general, the characteristics of the modern x86 instruction set are as follows: Compact encoding Variable length and alignment independent (encodes as little endian as all x86 architecture data) Mainly single-address and double-address instructions, i. H. the first operand is also the destination. Memory operands are supported both as source and destination (commonly used to read/write stack elements addressed with small direct offsets). Both general and indirect use of the register; Although all seven (counting ebp) general registers in 32-bit mode and all fifteen (counting rbp) general registers in 64-bit mode can be freely used as accumulators or for addressing, most of them are also used indirectly by some ( approximately) uses Special Instructions; Therefore, the affected registers must be temporarily saved (usually saved) if they are active during such instruction sequences. Implicitly generates conditional flags using most integer ALU instructions. It supports various addressing modes, including immediate, shifted, and scaled-index, but is machine-independent, with the exception of jumps (introduced as an extension of the x86-64 architecture). Holds the floating point on the register stack. This includes special support for atomic read, modify and write instructions (xchg, cmpxchg/cmpxchg8b, xadd and integer instructions in combination with the lock prefix). Stack Instructions The x86 architecture supports the hardware execution stack mechanism. Statements such as push, pop, call, and ret are used when the stack is properly aligned to pass parameters and allocate them to local memoryand for maintaining and restoring callback points. The ret-size directive is very useful for implementing space-efficient (and fast) calling conventions where the caller is responsible for reclaiming the space occupied by the parameters on the stack. There are several options when setting up a stack frame for a recursive local data storage routine; The high-level input instruction (introduced with the 80186) uses a procedural nesting depth argument as well as a local size argument and may be faster than more explicit register manipulation (e.g. push bp; mov bp, sp; sub sp , Size ). Whether it is faster or slower depends on the particular x86 processor implementation and the calling method used by the compiler, programmer, or specific program code; Most x86 code is designed to work with x86 processors from different manufacturers and processor generations, which means a wide range of microarchitecture and microcode solutions, as well as different design options at the gate and transistor level. A full range of addressing modes (including immediate and basic + offset), even for instructions such as push and pop, facilitate direct use of stacks for integer, float and address data, and the specifications and ABI mechanisms are relatively simple compared to some RISC architectures ( requires a more precise call information stack). The Integer ALU instructions for x86 assembler are standard math operations add, sub, mul, z idiv; logical operators and, or, xor, neg; Arithmetic and logical bit shift, sal/sar, shl/shr; rotate with and without carry, rcl/rcr, rol/ror, BCD arithmetic instruction completion, aaa, aad, daa and others. Floating-point instructions The x86 assembly language contains instructions for a stack-based floating-point unit (FPU). The FPU was an optional discrete coprocessor for the 8086–80386, was an optional chip for the 80486 series, and is a standard feature on every Intel x86 processor.from 80486 onwards Pentium. FPU instructions include addition, subtraction, negation, multiplication, division, remainder, square root, integer truncation, fractional truncation, and power of two scaling. The operations also include conversion instructions that can load or store a value from memory in any of the following formats: BCD, 32-bit integer, 64-bit integer, 32-bit floating point, 64-bit floating point, or 80-bit floating point. (after loading, the value is converted to the currently used floating point mode). The x86 also includes several transcendental functions, including sine, cosine, tangent, arctangent, exponent to base 2, and logarithms to 2, 10, or e. Instruction Stack Register The stack register format is typically fop st , st( n ), or fop st(n), st , where st is equivalent to st(0) and st(n) is one of the 8 stack registers (st(0), st(1), ..., st( 7)). Like integers, the first operand is both the first source operand and the first destination operand. fsubr and fdivr must be distinguished as the first substitute for the original operands before subtraction or division. Add, subtract, multiply, divide, store, and compare instructions include instruction modes that pop off the top of the stack when the operation is complete. For example, in faddp st(1), st evaluates to st(1) = st(1) + st(0), then pops st(0) off the top of the stack, resulting in st(1) on top of the stack. . stack st(0). SIMD Instructions Modern x86 processors contain SIMD instructions that perform almost the same operation in parallel with multiple values encoded in a wide SIMD register. Different instruction technologies support different operations with different register sets, but in general (from MMX to SSE4.2) they cover general calculations with integer or floating-point arithmetic (add, subtract, multiply, shift, minimize, maximize, compare). ,or square root). For example, paddw mm0, mm1 makes 4 parallel 16-bit integers (denoted w), adds (denoted padd) the values of mm0 to mm1, and stores the result in mm0. Streaming SIMD or SSE extensions also includes a floating point mode in which only the value of the first register (extended in SSE2) actually changes. Several other unusual instructions were added, including the sum of absolute differences (used to estimate motion in video compression, such as MPEG) and the 16-bit accumulate multiply instruction (useful in software alpha interpolation and digital filtering). SSE (since SSE3) and 3DNow! extensions include addition and subtraction instructions for handling floating point pairs such as complex numbers. These instruction sets also contain numerous subword constant instructions for shuffling, inserting, and extracting values in registers. In addition, there are instructions for moving data between integer registers and XMM (used in SSE)/FPU (used in MMX) registers. Memory Instructions The x86 processor also includes complex addressing modes for directly addressing shift memory, a register, a shift register, a scaled register with or without a shift, and an additional shift register and other scaled register. For example, you could code mov eax, [Table + ebx + esi*4] as a single instruction that reads 32 bits of data from an address calculated as (Table + ebx + esi * 4) offset from the ds selector and stores it. in the former register. In general, x86 processors can load and use memory according to the size of any register they operate in. (SIMD instructions also include half load instructions.) Most two-operand x86 instructions, including integer ALU instructions, use the standard "address mode byte" [12], often referred to as the MOD-REG- R/M byte. [13] [14][15] Many 32-bit x86 instructions also have a SIB address mode byte following MOD-REG-R/M.In principle, since the instruction opcode is separate from the addressing mode byte, these instructions are orthogonal because any of these opcodes can be mixed and matched with any addressing mode. However, the x86 instruction set is generally considered non-orthogonal because many other opcodes have some fixed addressing mode (they don't have an addressing mode byte) and each register is special. The x86 instruction set contains instructions for loading, storing, moving, scanning, and comparing strings (lods, stack, movs, scas, and cmps) that perform each operation with a specific size (b for an 8-bit byte, w for a 16-bit word, d for a 32-bit dword) and then increment/decrement (depending on DF, direction flag) the implicit address register (si for lods, di for stacks and scas, and for movs and cmps). For load, store, and scan operations, the default destination/source/compare register is al, ax, or eax (depending on size). Used implicit segment registers: ds for si and es for di. The cx or ecx register is used as a decrementing counter, and the operation stops when the counter reaches zero or (in the case of a scan and compare) when an inequality is found. The stack is implemented with implicit decrement (push) and increment (pop) of the stack pointer. In 16-bit mode this implicit stack pointer is addressed as SS:[SP], in 32-bit mode as SS:[ESP], and in 64-bit mode as [RSP]. The stack pointer actually points to the last saved value, assuming its size matches the CPU's mode of operation (i.e. 16, 32, or 64 bits) to match the default push/pop/call width. manual / ret. Also included are input and output instructions that reserve and remove data from the top of the stack when the stack frame pointer is set to bp/ebp/rbp. However, direct setting or addition and subtraction in sp/esp/rsp are also supported, so enter/leee statements are generally not needed. This code infunction: press ebp ; save stack frame call function (ebp) mov ebp, esp ; create a new stack frame above the stack of our calling subroutine, 4 ; the allocation of 4 bytes of stack space for this function's local variables ... is functionally equivalent only to: type 4, 0 Other stack manipulation instructions include pushf/popf for saving and loading the (E)FLAGS register. The push/pop instruction saves and loads the state of the entire integer register to and from the stack. It is assumed that the loading or storing of SIMD values is packed into adjacent positions of the SIMD register and arranged in a low sequential order. Some SSE load and store instructions require 16-byte alignment to function properly. SIMD instruction sets also contain "prefetch" instructions that perform the load but do not refer to any registers used for fetching from the cache. SSE instruction sets also contain short-term storage instructions that will perform storage directly in memory without cache allocation if the target is not already in the cache (otherwise it will function as normal memory). without a SIMD instruction) can use one parameter as a composite address as a second source parameter. Integer instructions can also accept a single memory parameter as the destination operand. The X86 assembler program flow has an unconditional jump operation, jmp, which can take a direct address, a register, or an indirect address as a parameter (note that most RISC processors only support a linear register or a short direct offset for a jump). Several conditions are also supported, including jz (jump to zero), jnz (jump to non-zero), jg (jump to greater than signed), jl (jump to less than signed), if (jump to / greater than for, unsigned), jb (jump down/less than, unsigned). These conditional actions are based on the state of certain bits in the (E)FLAGS register. A set of many arithmetic and logical operations, clear orthese symptoms depending on their outcome. The Compare cmp and test instructions set flags as if they were performing a subtraction or bitwise AND operation without changing the values of the operand. There are also operators such as clc (clear carry flag) and cmc (complement carry flag) that operate directly on flags. Floating point comparisons are performed using the fcom or ficom instructions, which must eventually be converted to integer flags. Each jump operation has three different forms depending on the size of the operand. A short jump uses a signed 8-bit operand that represents a relative deviation from the current instruction. A fast jump is similar to a short jump, but uses a signed 16-bit operand (in real or protected mode) or a signed 32-bit operand (in 32-bit protected mode only). The long jump uses the value of the entire base:offset segment as the absolute address. There are also indirect and indexed forms of each. In addition to simple jump operations, there are call (call a subroutine) and ret (return from a subroutine) instructions. Before transferring control to the calling subroutine, it pushes onto the stack the offset address of the instruction segment following the call; ret pops that value off the stack and jumps to it, effectively returning flow of control to that part of the program. On a remote call, the base of the segment is shifted; Far ret skips the offset and then returns the base of the segment. There are also two similar instructions, int (interrupt), which pushes the current value of the (E)FLAGS register onto the stack and then makes a remote call, except that an index in the table is used instead of the interrupt vector. address is being used. Interrupt handler addresses. An interrupt handler typically saves all other CPU registers it uses, except when they are used to return the result of an operation to the calling program (called an interrupt in software). Appropriate interrupt returnyou can restore the flags when you return. Soft interrupts of the type described above are used by some operating systems for system calls and can also be used when debugging hard interrupt handlers. Latch interrupts are triggered by external hardware events and must write all register values because the state of the currently executing program is unknown. In protected mode, the operating system can set interrupts to trigger a task switch that automatically saves all registers for the active task. Examples This article may contain original research. Correct it by checking the statements made and adding quotation marks. Submissions containing only original studies should be deleted. (March 2013) (Learn how and when to remove this post template) "Hello world!" A DOS program in MASM-style assembly language. Using interrupt 21h for output - other examples use printf from libc to print to stdout.[22] .model small .stack 100h .data msg db 'Hello world!$' .code start: mov ah, 09h ; Show message lea dx, msg int 21h mov ax, 4C00h ; Exit the executable int 21h end start "Hello world!" a program for Windows on MASM-style assembly language; requires /coff switch in version 6.15 and earlier. 386 near external exit: near public main process push offset msg call printf push 0 call output main endp end "Hello world!" NASM-style assembly program for Windows; Image Base = 0x00400000 %define RVA(x) (x-0x00400000) section .text push iwd hello call iwd [printf] push byte +0 call iwd [exit] ret section .data hello db "Hello world!" section .idata dd RVA(msvcrt_LookupTable) dd -1 dd 0 dd RVA(msvcrt_string) dd RVA(msvcrt_imports) times 5 dd 0 ; exit descriptor table msvcrt_string dd "msvcrt.dll", 0 msvcrt_LookupTable: dd RVA(msvcrt_printf) dd RVA(msvcrt_exit) dd 0printf dd RVA(msvcrt_printf) exit dd RVA(msvcrt_exit) dd 0 msvcrt_printf: dw 1 dw "printf", 0 msvcrt_exit: dw 2 dw "exit", 0 dd 0 "Hello world!" A NASM-style assembler program for Linux; ; This program runs in 32-bit protected mode. ; compile: nasm -f elf -F stab name.asm ; link: ld -o name name.o ; ; In 64-bit long mode, you can use 64-bit registers (eg rax instead of eax, rbx instead of ebx, etc.); Also change "-fe elf" to "-fe elf64" in the build command. ; section .data; section for initialized data str: db 'Hello world!', 0Ah ; message string with trailing newline (10 decimal places) str_len: equ $ - str ; calculates the length of a string (in bytes) by subtracting the starting address of the string; from this address ($ symbol) section .text ; this is the global code part _start; _start is the entry point and requires the global scope to be "visible" to ; linker -- C/C++ equivalent of main() _start: ; procedure definition starts here _start mov eax, 4 ; enter sys_write function code (from operating system vector table) mov ebx, 1 ; specify stdout file descriptor -- in gnu/linux everything is treated as a file; i hardware devices mov ecx, str ; move start of message string _address_ to register ecx mov edx, str_len ; length of transmitted message (in bytes) int 80h ; interrupt the kernel to make the system call we just set up -; on gnu/linux services are required by the kernel mov eax, 1 ; enter function code sys_exit (from OS vector table) mov ebx, 0 ; enter the return code for the operating system (zero tells the system that everything went well) int 80h ; interrupt the kernel and make a system call (to exit) "Hello world!" A NASM-style assembly language program for Linux using the C standard library; ; This program runs in 32-bit protected mode. ; gcc links the C standard library by default; compile: nasm -f elf -F stab name.asm ; link: gcc -o name name.o ; ; In 64-bit long mode, you can use 64-bit registers (eg rax instead of eax, rbx instead of ebx, etc.); Also change "-fe elf" to "-fe elf64" in the build command. ; Global;main must be defined because it is compiled against the C standard library. extern printf ;declares the use of an external symbol because printf is declared in another object module. ;The linker will resolve this symbol later. segment .data ;Section for initialized data string db 'Hello World!', 0Ah, 0h ;Message string with newline characters (10 decimal places) and NULL termination ;The string now points to the starting address where 'Hello World' is stored. segment .text main: push string; put the address of the first character of the string on the stack. This will be the argument to printf to call printf ;call printf add esp, 4 ;advance the stack pointer by 4 and flush the pushed string argument ret ;return "Hello world!" Program for 64-bit mode in Linux NASM; build: nasm -f elf64 -F dwarf hello.asm ; Link: ld -o hello hello.o DEFAULT REL ; default RIP relative addressing modes so [foo] = [rel foo] SECTION .rodata ; read-only data can be placed in .rodata on GNU/Linux, for example .rdata on Windows Hello: db "Hello world!",10 ; 10 = "". len_hello: equ $-hello ; tell NASM to calculate the length as an assembly time constant ;; Write() is fixed length, so there is no need for a C-style 0-terminated string. This should be placed in SECTION .text global _start _start: mov eax, 1 ; __NR_write system call number from Linux asm/unistd_64.h (x86_64) mov edi, 1 ; int fd = STDOUT_FILENO lea rsi, [rel hello] ; x86-64 uses RIP relative LEA to set static addresses in regs mov rdx, len_Hello ; size_t count = len_Hello system call ; write(1, Hello len_Hello); Invoke the kernel to actually make the system call; returns the value of RAX. RCX and R11 also suppress the syscall mov eax, 60 ; __NR_Output phone number (x86_64) xor edi, edi ; status = 0 (normal exit) syscall ; _exit(0) The pod strace execution checks that the process does not make any further system calls. The printf version would make many more system calls to initialize libc and dynamically link. But it's a static executable because we linked with ld-cake or any shared libraries; the only instructions that work in userspace are the ones you provide. $ strace ./hello > /dev/null # no redirection, your program's standard output is mixed strace logging to stderr. Which is mostly good. ? +++ ends 0 +++ Flag usage Flags are often used for comparison on the x86 architecture. When comparing two pieces of data, the CPU sets the appropriate flag or flags. You can then use conditional jump commands to test for flags and branch to the code to be executed, for example: cmp eax, ebx etc do_something ; ... Do something: ; do something here Flags are also used in the x86 architecture to enable or disable certain functions or execution modes. For example, to disable all maskable interrupts, you can use the following command: cli You can also directly access the flag register. The lower 8 bits of the flag register can be loaded into ah using the lahf instruction. The entire flag register can also be moved to and from the stack using the pushf, popf, int (including do), and iret instructions. Using the Instruction Pointer Register The instruction pointer is called ip in 16-bit mode, eip in 32-bit mode, and rip in 64-bit mode. The instruction pointer register specifies the memory address that the processor will then attempt to execute; it cannot be accessed directly in 16-bit or 32-bit mode, but you can write the following sequence to pop the next_line address into eax: call next_line next_line: pop eax This sequence of instructions generates position-independent code because the call takes an immediate operand relative to the instruction pointer that describes the byte offset of the destination instruction from the next instruction (0 in this case). Writing to the instruction pointer is simple - the jmp instruction sets the instruction pointer to the target address, so for example a sequence likethe following puts the contents of eax into eip: jmp eax In 64-bit mode, instructions can refer to data relative to the instruction pointer, so there is no need to copy the value of the instruction pointer to another register. See also List of instructions for the X86 symbolic instruction language. X86 architecture. Processor design. List of self-modifying DOS assembler code. ^ "The Intel 8008 Microprocessor Family (i8008)". www.cpu-world.com. Retrieved March 25, 2021 PROCESSOR MUSEUM - MICROPROCESSOR MUSEUM AND PHOTOS. Retrieved March 25, 2021 ^ a b c "OKY Intel 8008". www.pastaraiser.com. Retrieved March 25, 2021 ^ "Assembly Language Handbook". www.ibm.com. Retrieved November 28, 2022 ^ "X86 Assembly Language Reference Manual" (PDF). ^ a b c d e Narayam, Ram (October 17, 2007). "Linux Assemblers: Comparing GAS and NASM". IBM. Archived from the original on October 3, 2013. Retrieved July 2, 2008 ^ "The Making of Unix". Archived from the original on April 2, 2014. ^ Hyde, Randall. "Which assembler is better?". Retrieved May 18, 2008. ^ "GNU Assembler News, v2.1 supports Intel syntax". 2008-04- 04. Retrieved July 2, 2008. ^ "i386-Errors (use as)". Documentation binutils. ^ Retrieved January 15, 2020. ↑ Muller, Scott (March 24, 2006). "Second generation of P2 processors (286)". PC Upgrade and Repair 17th Edition (Book) (17th edition). Que. ISBN 0-7897-3404-4. Retrieved December 6, 2017. Bibliography "8086 Instruction Coding". ^ Igor Kholodov. “6. Instruction operand encoding x86, bytes MOD-REG-R / M". ^ "x86 instruction encoding". Bibliography "The Zen of Assembly Language: Volume I, Knowledge". "Chapter 7: Memory Addressing". -reg-rm". ^ Intel 80386 Developer's Reference Guide. "17.2.1 ModR/M and SIB Bytes" ^ "X86-64 Instruction Encoding: ModR/M and SIB Bytes" ^ "Figure 2-1. Instruction format for Intel 64 and IA-32 architectures.Wish list". ^ "Just started assembly". Ed, Jorgensen (May 2018). x86-64 assembly language programming with Ubuntu (PDF) (rev. 1.0.97). Page 367. Retrieved from " .wikipedia.org/w/index.php?title=X86_Assembly_Language&oldid=1131791886" " "
no reviews yet
Please Login to review.