asm.sh ====== asm.sh is an assembler embedded into POSIX shell. It defines functions for all (supported) i386 instructions. It generally follows AT&T syntax, modified in many places to avoid characters reserved by the shell. Arguments are separated by spaces, no comma allowed (as usual in shell). Width suffixes are generally mandatory. Labels ------ There are two kinds of label: Global and local labels. Global labels are defined with the `label' function, e.g.: label _start They must be globally unique. Global labels are referred to by their name, e.g. `_start'. They can also be relative; the following defines a label `offset' whose value is the difference between the current location and the value of the label `base': label offset base Local labels are defined with the `L' function, e.g.: L loop There can be several definitions of a local label. There are two ways to refer to a local label: - `loop^' refers to the previous declaration of the label - `loop.' refers to the next declaration of the label Operands -------- Immediates: Either a label, or an integer literal in decimal, octal (preceded by 0) or hexadecimal (preceded by 0x). Registers: Preceded by `%' as in AT&T, e.g. `%eax'. Memory operands: Start with `@', followed by a sum expression. Examples: AT&T | asm.sh -------------------|------------------- 0x100 | @0x100 label | @label 4(%eax) | @%eax+4 4(,%eax) | @1%eax+4 14(,%eax,2) | @14+2%eax (%eax,%ebx) | @%eax+%ebx (%ebx,%eax) | @%ebx+%eax (%ebx,%eax) | @1%eax+%ebx 12(%ebx,%eax,8) | @%ebx+8%eax+12 The order of the summands is generally irrelevant, except that if there are two unscaled registers, the first is taken to be the base and the second the index. Displacement can be a label, scale must be one of the literal characters 1, 2, 4, or 8 (or omitted, implicitly 1). Calling convention ================== The first three arguments are passed in %eax, %ecx and %edx. Remaining arguments are passed on the stack in right-to-left order (last argument is pushed first), and cleaned up by the callee. The return value currently always fits in three registers; it is placed in %eax, %ecx, and %edx. Some functions also modify EFLAGS, e.g. streq sets ZF iff the strings are equal. Functions may clobber %eax, %ecx and %edx. Stack must be 4-byte aligned. Porting ======= To port to other operating systems, it should be sufficient to modify asm.sh (for the ELF header) and start.asm (for system calls etc).