Annotation of wikisrc/examples/netbsd_assembly.mdwn, revision 1.1

1.1     ! mspo        1: **Contents**
        !             2: 
        !             3: [[!toc levels=3]]
        !             4: 
        !             5: #   Assembly? 
        !             6: 
        !             7: _Assembly_ is the programming language that gives direct access to the instructions and registers of the processor. A program called the _assembler_ compiles assembly language into machine code. NetBSD installs the GNU assembler "gas" into /usr/bin/as and this program assembles for the host processor architecture. 
        !             8: 
        !             9: A higher-level compiler like "gcc" acts as a preprocessor to the assembler, by translating code from C (or other language) to assembler. Just run cc -S yourfile.c and look at the output yourfile.s to see assembly code. A higher-level compiler can probably write better assembly code than a human programmer who knows assembly language. 
        !            10: 
        !            11: There remain a few reasons to use assembly language. For example: 
        !            12: 
        !            13:   * You need direct access to processor registers (for example, to set the stack pointer). 
        !            14:   * You need direct access to processor instructions (like for vector arithmetic or for atomic operations). 
        !            15:   * You want to improve or fix the higher-level compiler, assembler, or linker. 
        !            16:   * You want to optimize code, because your higher-level compiler was not good enough. 
        !            17:   * You want to learn assembly language. 
        !            18: 
        !            19: #   i386 
        !            20: 
        !            21: _i386_ architecture takes its name from the Intel 386, the first x86 processor to have a 32-bit mode. Other names for this architecture are: 
        !            22: 
        !            23:   * _IA-32_, which means Intel Architecture, 32 bit. 
        !            24:   * _x86_, which can mean the 32-bit mode or the ancient 16-bit mode. 
        !            25: 
        !            26: The i386 assembly language is either AT&T syntax or Intel syntax. Most programmers seem to prefer the Intel syntax. 
        !            27: 
        !            28: ##   nasm 
        !            29: 
        !            30: NASM (the Netwide Assembler) is a x86 assembler that uses the Intel syntax. It is easily available via [devel/nasm](http://pkgsrc.se/devel/nasm#main). 
        !            31: 
        !            32: You can also use [devel/yasm](http://pkgsrc.se/devel/yasm#main) with [devel/nasm](http://pkgsrc.se/devel/nasm#main) syntax. 
        !            33: 
        !            34: 
        !            35: ###   Hello world, NetBSD/i386 
        !            36:     
        !            37:     ; Hello world, NetBSD/i386 4.0
        !            38:     
        !            39:     section .note.netbsd.ident progbits alloc noexec nowrite
        !            40:        dd 0x00000007 ; Name size
        !            41:        dd 0x00000004 ; Desc size
        !            42:        dd 0x00000001 ; value 0x01
        !            43:        db "NetBSD", 0x00, 0x00 ; "NetBSD\0\0"
        !            44:        db 400000003 ; __NetBSD_Version__ (please see <sys/param.h>)
        !            45:     
        !            46:     section .data
        !            47:        msg db "Hello world!", 0x0a ; "Hello world\n"
        !            48:        len equ $ - msg
        !            49:     
        !            50:     section .text
        !            51:        global _start
        !            52:     
        !            53:     _start:
        !            54:        ; write()
        !            55:        mov eax, 0x04 ; SYS_write
        !            56:        push len ; write(..., size_t nbytes)
        !            57:        push msg ; write(..., const void *buf, ...)
        !            58:        push 0x01 ; write(int fd, ...)
        !            59:        push 0x00
        !            60:        int 0x80
        !            61:        pop ebx
        !            62:     
        !            63:        ; exit()
        !            64:        mov eax, 0x01 ; SYS_exit
        !            65:        push 0x00 ; exit(int status)
        !            66:        push 0x00
        !            67:        int 0x80
        !            68:     
        !            69: 
        !            70: ###   How to compile and link 
        !            71: 
        !            72: To use the above codes you need to compile and then link them: 
        !            73:     
        !            74:     $ nasm -f elf hello.asm
        !            75:     $ ld -o hello hello.o
        !            76:     $ ./hello
        !            77:     Hello world!
        !            78:     
        !            79: 
        !            80: ##   gas 
        !            81: 
        !            82: _the portable GNU assembler_
        !            83: 
        !            84: It uses AT&T syntax and designed after the 4.2BSD assembler. You can use it on many CPU architectures. 
        !            85: 
        !            86: Example: 
        !            87:     
        !            88:     
        !            89:     .section ".note.netbsd.ident", "a"
        !            90:             .long   2f-1f
        !            91:             .long   4f-3f
        !            92:             .long   1
        !            93:     1:      .asciz  "NetBSD"
        !            94:     2:      .p2align 2
        !            95:     3:      .long   400000000
        !            96:     4:      .p2align 2
        !            97:     
        !            98:     .section .data
        !            99:         data_items:                                # this is an array
        !           100:             .long 3,39,41,21,42,34,42,23,38,37,15,37,16,17,18,25,23,12,31,2
        !           101:             .set DATASIZE, ( . - data_items) / 4 - 1
        !           102:     
        !           103:     .section .text
        !           104:         .globl _start
        !           105:     
        !           106:         _start:
        !           107:             movl    $0, %edi                        # zero the index register
        !           108:             movl    $DATASIZE, %ecx                 # set ecx to number of items
        !           109:             movl    data_items(,%ecx,4), %eax       # load first item
        !           110:             movl    %eax, %ebx                      # its the biggest atm
        !           111:     
        !           112:         main_loop:
        !           113:             decl    %ecx                            # decrement counter
        !           114:             movl    data_items(,%ecx,4), %eax       # step to next element
        !           115:             cmpl    %eax, %ebx                      # is it greater?
        !           116:             cmovll  %eax, %ebx                      # set ebx to greater if its less
        !           117:      than cur. num.
        !           118:             jecxz   end_prog                        # if we are at item 0 end iterat
        !           119:     ion
        !           120:             jmp     main_loop                       # again!
        !           121:     
        !           122:         end_prog:
        !           123:             pushl   %ebx                            # return largest number
        !           124:             pushl   %ebx                            # BSD-ism (has to push twice?)
        !           125:             movl    $1, %eax                        # call exit
        !           126:             int     $0x80                           # kernel
        !           127:             ret
        !           128:     
        !           129: 
        !           130: #   powerpc 
        !           131: 
        !           132: _PowerPC_ processors appear inside multiple different hardware platforms; NetBSD has at least 11 ports, see [[Platforms#PowerPC]]. The easiest way to obtain a PowerPC machine is probably to acquire a used Macintosh, choosing from among the [supported models for NetBSD/macppc](http://www.netbsd.org/ports/macppc/models.html). 
        !           133: 
        !           134: PowerPC processors have 32-bit registers and pointers and use big-endian byte order. 
        !           135: 
        !           136:   * A very few boards (not with NetBSD) run the PowerPC in little-endian mode to match the hardware. 
        !           137:   * A few PowerPC processors also have a 64-bit mode. NetBSD 5.0 will support some Apple G5 machines with these processors, but only in 32-bit mode (see [ppcg5 project](http://netbsd-soc.sourceforge.net/projects/ppcg5/)). 
        !           138: 
        !           139: 
        !           140: ##   gas 
        !           141: 
        !           142: Here is an example of a program for gas: 
        !           143:     
        !           144:     
        !           145:     ##  factorial.s
        !           146:     ##  This program is in the public domain and has no copyright.
        !           147:     ###
        !           148:     ##  This is an example of an assembly program for NetBSD/powerpc.
        !           149:     ##  It computes the factorial of NUMBER using unsigned 32-bit integers
        !           150:     ##  and prints the answer to standard output.
        !           151:     
        !           152:        .set    NUMBER, 10
        !           153:        
        !           154:     .section ".note.netbsd.ident", "a"
        !           155:        
        !           156:        #  ELF note to identify me as a native NetBSD program
        !           157:        #  type = 0x01, desc = __NetBSD_Version__ from <sys/param.h>
        !           158:        ##      
        !           159:        .int    7                       # length of name        
        !           160:        .int    4                       # length of desc
        !           161:        .int    0x01                    # type
        !           162:        .ascii  "NetBSD\0"              # name
        !           163:        .ascii  "\0"                    # padding
        !           164:        .int    500000003               # desc
        !           165:     
        !           166:     .section ".data"
        !           167:        
        !           168:     decbuffer:
        !           169:        .fill   16                      # buffer for decimal ASCII
        !           170:     decbufend:
        !           171:        .ascii  "\n"                    # newline at end of ASCII
        !           172:        
        !           173:     .section ".text"
        !           174:        
        !           175:        #  PowerPC instructions need an alignment of 4 bytes
        !           176:        .balign 4
        !           177:        
        !           178:        .globl  _start
        !           179:        .type   _start, @function
        !           180:     _start:
        !           181:        #  compute factorial in %r31
        !           182:        li      %r0, NUMBER
        !           183:        mtctr   %r0                     # ctr = number
        !           184:        li      %r31, 1                 # %r31 = factorial
        !           185:        li      %r30, 1                 # %r30 = next factor
        !           186:     factorial_loop:
        !           187:        mullw   %r31, %r31, %r30        # multiply %r31 by next factor
        !           188:        addi    %r30, %r30, 1           # increment next factor
        !           189:        bdnz+   factorial_loop          # loop ctr times
        !           190:     
        !           191:        #  prepare to convert factorial %r31 to ASCII.
        !           192:        lis     %r9, decbufend@ha
        !           193:        la      %r4, decbufend@l(%r9)   # %r4 = decbufend
        !           194:        lis     %r8, decbuffer@ha
        !           195:        la      %r29, decbuffer@l(%r8)  # %r29 = decbuffer
        !           196:        li      %r5, 1                  # %r5 = length of ASCII
        !           197:     
        !           198:        #  Each loop iteration divides %r31 by 10 and writes digit to
        !           199:        #  position %r4. Formula (suggested by gcc) to divide by 10,
        !           200:        #                     0xcccccccd
        !           201:        #  is to multiply by ----------- = 0.100000000005821
        !           202:        #                    0x800000000
        !           203:        #  which is to multiply by 0xcccccccd, then shift right 35.
        !           204:        ##
        !           205:        .set    numerator, 0xcccccccd
        !           206:        lis     %r9, numerator@ha
        !           207:        la      %r28, numerator@l(%r9)  # %r28 = numerator
        !           208:     decloop:
        !           209:        cmpw    %r29, %r4               # start of buffer <=> position
        !           210:        beq-    buffer_overflow
        !           211:        #  begin %r9 = (%r31 / 10)
        !           212:        mulhwu  %r9, %r31, %r28         # %r9 = ((%r31 * %r28) >> 32)
        !           213:        addi    %r4, %r4, -1            # move %r4 to next position
        !           214:        srwi    %r9, %r9, 3             # %r9 = (%r9 >> 3) = %r31 / 10
        !           215:        mulli   %r8, %r9, 10            # %r8 = (%r31 / 10) * 10
        !           216:        sub     %r27, %r31, %r8         # %r27 = %r31 % 10 = digit
        !           217:        addi    %r27, %r27, '0          # convert digit to ASCII
        !           218:        addi    %r5, %r5, 1             # count this ASCII digit
        !           219:        stb     %r27, 0(%r4)            # write ASCII digit to buffer
        !           220:        mr.     %r31, %r9               # %r31 /= 10, %r31 <=> 0
        !           221:        bne+    decloop                 # loop until %r31 == 0
        !           222:        #  FALLTHROUGH
        !           223:     
        !           224:     buffer_overflow:
        !           225:        #  write(2) our factorial to standard output
        !           226:        li      %r0, 4                  # SYS_write from <sys/syscall.h>
        !           227:        li      %r3, 1                  # standard output
        !           228:        ##      %r4                     # buffer
        !           229:        ##      %r5                     # size of buffer
        !           230:        sc
        !           231:     
        !           232:        #  exit(2)
        !           233:        li      %r0, 1                  # SYS_exit from <sys/syscall.h>
        !           234:        li      %r3, 0                  # exit status
        !           235:        sc
        !           236:     
        !           237:        .size   _start, . - _start
        !           238:     
        !           239: 
        !           240: With a NetBSD/powerpc system, you can run this program using 
        !           241:     
        !           242:     $ as -o factorial.o factorial.s
        !           243:     $ ld -o factorial factorial.o
        !           244:     $ ./factorial
        !           245:     3628800
        !           246:     $
        !           247:     
        !           248: 
        !           249: ##   Useful Documents 
        !           250: 
        !           251: To learn about PowerPC assembly language, here are two documents to start with. 
        !           252: 
        !           253:   * IBM developerWorks. [PowerPC Assembly](http://www.ibm.com/developerworks/library/l-ppc/). This is a very good introduction to PowerPC assembly. It provides and explains the Hello World example (but using a Linux system call). 
        !           254:   * SunSoft and IBM. [System V Application Binary Interface, PowerPC Processor Supplement](http://refspecs.linux-foundation.org/elf/elfspec_ppc.pdf) (PDF file, hosted by Linux Foundation). This is the specification for 32-bit PowerPC code in ELF systems. It establishes %r1 as the stack pointer and describes the stack layout. It explains the C calling conventions, how to pass arguments to and return values from C functions, how to align data structures, and which registers to save to the stack. 
        !           255: 
        !           256:     * NetBSD, Linux and OpenBSD (and FreeBSD?) all use ELF with PowerPC and all follow this specification, with a few deviations and extensions. 
        !           257: 
        !           258: ##   Wiki Pages 
        !           259: 
        !           260:   * [[ELF Executables for PowerPC]]. This introduces assembly language with a commented example. 
        !           261: 

CVSweb for NetBSD wikisrc <wikimaster@NetBSD.org> software: FreeBSD-CVSweb