//---------------------------------------------------------------- // tryfork.s // // This program directly invokes the 'fork' system-call in // order to create a 'child' process; the 'parent' process // then issues the 'waitpid' system-call, causing it to be // 'blocked' until the child-process has terminated. Both // processes display a small number of their topmost stack // elements, for comparison purposes. // // assemble using: $ as tryfork.s -o tryfork.o // and link using: $ ld tryfork.o -o tryfork // // date begun: 06 NOV 2003 // completion: 07 NOV 2003 // revised on: 11 NOV 2003 //---------------------------------------------------------------- # manifest constants .equ sys_EXIT, 1 .equ sys_FORK, 2 .equ sys_WRITE, 4 .equ sys_WAITPID, 7 .equ STDOUT, 2 .section .data pid: .int -1 # holds the process-ID hexlst: .ascii "0123456789ABCDEF" # list of hex numerals status: .int 0 # status for 'waitpid' pfini: .ascii "\nparent is finished.\n\n" .equ pfsz, . - pfini cfini: .ascii "\nchild is finished.\n\n" .equ cfsz, . - pfini .section .text _start: # issue the 'fork' system-call movl $sys_FORK, %eax # service ID-number int $0x80 # enter the kernel movl %eax, pid # save return-value # branch to different threads orl %eax, %eax # was zero returned? jnz parent # no, it's the parent jmp child # else it's the child terminate: # issue the 'exit' system-call movl $sys_EXIT, %eax # service ID-number movl $0, %ebx # process exit-code int $0x80 # enter the kernel #----------------------------------------------------------------- parent: # go to sleep until the child-process has terminated movl $sys_WAITPID, %eax # service ID-number movl pid, %ebx # process to wait for movl $status, %ecx # address for status movl $0, %edx # service options int $0x80 # enter the kernel # display the topmost stack-elements call show_stack # display stack items # print a termination notification movl $sys_WRITE, %eax # service ID-number movl $STDOUT, %ebx # device-handle movl $pfini, %ecx # message address movl $pfsz, %edx # message length int $0x80 # enter the kernel jmp terminate # goto exit-routine #----------------------------------------------------------------- child: # display the topmost stack-elements call show_stack # display stack items # print a termination notification movl $sys_WRITE, %eax # service ID-number movl $STDOUT, %ebx # device-handle movl $cfini, %ecx # message address movl $cfsz, %edx # message length int $0x80 # enter the kernel jmp terminate # goto exit-routine #----------------------------------------------------------------- show_stack: # # This procedure is called by both of the processes, to display # a few of the topmost elements on their stacks. (It allocates # some storage-space (128 bytes) on their respective stacks for # its temporary use as a buffer-area, but releases that storage # before exiting back to the calling procedure.) # push %ebp # save frame-pointer movl %esp, %ebp # setup our own frame subl $128, %esp # allocate buffer area pushal # preserve registers # prepare registers for string-processing leal -128(%ebp), %edi # point EDI to buffer-area movl %ebp, %esi # point ESI to stack-frame cld # use forward processing # write stack-frame's address to buffer-area movl %esi, %eax # copy address into EAX call eaxout # write EAX as hex-value movb $':', %al # then append a colon stosb # following the address # write topmost stack elements to buffer-area movl $7, %ecx # number of stack-items nxdwd: movb $' ', %al # prepend a blank space stosb # before next hex-value lodsl # fetch next stack-item call eaxout # write item as hex-value loop nxdwd # process remaining items # display the sequence of stack elements movl $sys_WRITE, %eax # service ID-number movl $STDOUT, %ebx # device-handle leal -128(%ebp), %ecx # message address movl %edi, %edx # end-of-message subl %ecx, %edx # minus its start int $0x80 # enter the kernel popal # restore registers movl %ebp, %esp # discard buffer area pop %ebp # recover frame-pointer ret # return to caller #----------------------------------------------------------------- eaxout: # # This helper-function converts the value found in register EAX # to its representation as a hexadecimal digit-string at (EDI), # and advances the address in EDI to the next buffer position. # pushl %eax # preserve work registers pushl %ebx pushl %ecx pushl %edx movl %eax, %edx # copy EAX value to EDX movl $hexlst, %ebx # point EBX to digit-list movl $8, %ecx # the number of nybbles nxnyb: roll $4, %edx # next nybble into DL movb %dl, %al # copy nybble into AL andb $0xF, %al # isolate the nybble xlat # convert nybble to hex stosb # store digit to buffer loop nxnyb # process rest of nybbles popl %edx # restore saved registers popl %ecx popl %ebx popl %eax ret # return to caller #----------------------------------------------------------------- .globl _start # make symbol visible