Archetypical Example: Euclid's Method of Computing Greatest Common Divisors (assembler, return address on separate stack) 超典型的ソースコードの見本~最大公約数を計算する、ユークリッドの互除法 (アセンブラ、帰還位置を別のスタックに)
- .file "gcddummy.c"
- /* Not optimizing, to keep parallel with real compile. */
- /* Shims for n parameter single-stack functions (4 byte parameters) */
- /* The target address is in %eax */
- .text
- .globl shim5p
- .type shim5p, @function
- shim5p:
- pushl 16(%ebp)
- pushl 12(%ebp)
- pushl 8(%ebp)
- pushl 4(%ebp)
- pushl (%ebp)
- call *%eax
- addl $20, %esp
- ret
- .size shim5p, .-shim5p
- .text
- .globl shim4p
- .type shim4p, @function
- shim4p:
- pushl 12(%ebp)
- pushl 8(%ebp)
- pushl 4(%ebp)
- pushl (%ebp)
- call *%eax
- addl $16, %esp
- ret
- .size shim4p, .-shim4p
- .text
- .globl shim3p
- .type shim3p, @function
- shim3p:
- pushl 8(%ebp)
- pushl 4(%ebp)
- pushl (%ebp)
- call *%eax
- addl $12, %esp
- ret
- .size shim3p, .-shim3p
- .text
- .globl shim2p
- .type shim2p, @function
- shim2p:
- pushl 4(%ebp)
- pushl (%ebp)
- call *%eax
- addl $8, %esp
- ret
- .size shim2p, .-shim2p
- .text
- .globl shim1p
- .type shim1p, @function
- shim1p:
- pushl (%ebp)
- call *%eax
- addl $4, %esp
- ret
- .size shim1p, .-shim1p
- .text
- .globl gcd
- .type gcd, @function
- gcd:
- pushl %ebp /* Frame for unwinding */
- subl $4, %ebp /* Locals */
- jmp .L2
- .L3:
- movl 4(%ebp), %eax /* numA */
- cmpl 8(%ebp), %eax /* numB */
- jge .L4
- movl 4(%ebp), %eax /* numA */
- movl %eax, (%ebp) /* temp */
- movl 8(%ebp), %eax /* numB */
- movl %eax, 4(%ebp) /* numA */
- movl (%ebp), %eax /* temp */
- movl %eax, 8(%ebp) /* numB */
- .L4:
- movl 8(%ebp), %eax /* numB */
- subl %eax, 4(%ebp) /* numA */
- .L2:
- movl 4(%ebp), %eax /* numA */
- cmpl 8(%ebp), %eax /* numB */
- jne .L3
- movl 4(%ebp), %eax /* numA */
- popl %ebp /* Restore previous frame */
- ret
- .size gcd, .-gcd
- .section .rodata
- .LC0:
- .string "usage: %s <numA> <numB>\n"
- .align 4
- .LC1:
- .string "\tto calculate the greatest common divisor\n\tof two unsigned numbers."
- .LC2:
- .string "greatest common divisor: %ld\n"
- .LC3:
- .string "%ld/%ld => %ld/%ld\n"
- .align 4
- .LC4:
- .string "%s is not an unsigned number I can recognize.\n"
- .align 4
- .LC5:
- .string "Failed to allocate parameter stack in %s, errno: %d.\n"
- .align 4
- .type .LSSH0, @object
- .size .LSSH0, 5
- .LSSH0:
- .string "main"
- .text
- .globl main
- .type main, @function
- main:
- leal 4(%esp), %ecx
- andl $-16, %esp
- pushl -4(%ecx)
- pushl %ebp
- movl %esp, %ebp
- pushl %esi
- pushl %ebx
- pushl %ecx
- subl $60, %esp
- call __i686.get_pc_thunk.bx
- addl $_GLOBAL_OFFSET_TABLE_, %ebx /* strings */
- movl %ecx, %esi /* main arguments' base address */
- movl 4(%esi), %eax
- movl %eax, -48(%ebp)
- movl __guard_local@GOTOFF(%ebx), %eax
- movl %eax, -16(%ebp)
- xorl %eax, %eax
- /* Allocate the stack (in gcddummy.c)
- movl $4, 4(%esp)
- movl $1024, (%esp)
- call calloc@PLT
- // Do it way up high, instead.
- */
- call __errno@PLT /* Clear errno. */
- movl $0, (%eax)
- /* Make sure there's room on the stack for seven parameters. */
- subl $28, %esp
- /* address suggestion, 64Mb below system supplied stack. */
- leal -65536*1024(%esp), %eax
- movl %eax, (%esp)
- movl $65536, 4(%esp) /* size, 64Kb */
- movl $3, 8(%esp) /* PROT_READ | PROT_WRITE allowed */
- /* MAP_PRIVATE | MAP_ANONYMOUS | MAP_TRYFIXED mode flags */
- movl $4098, 12(%esp)
- movl $-1, 16(%esp) /* file descriptor to map to (none). */
- movl $0, 20(%esp) /* offset of mapping */
- movl $0, 24(%esp) /* parameter list terminator, I think. */
- call mmap@PLT
- addl $28, %esp /* Remove the parameters. */
- movl %eax, -36(%ebp) /* pstack (gcddummy.c) */
- call __errno@PLT
- movl (%eax), %eax
- cmpl $0, %eax
- je myentry
- movl %eax, 8(%esp) /* errno. (3 paramaters is within static allocation.) */
- movl -48(%ebp), %eax /* argv */
- movl (%eax), %eax /* argv[ 0 ] */
- movl %eax, 4(%esp)
- leal .LC5@GOTOFF(%ebx), %eax
- movl %eax, (%esp)
- call printf@PLT
- movl $1, %eax /* EXIT_FAILURE */
- jmp myexit
- myentry:
- movl -36(%ebp), %eax /* pstack */
- movl %eax, 4(%esp) /* Remember the lower bounds/alloc address. */
- /* Shift bp to the parameter stack pointer safely. */
- leal 1020*4(%eax), %edx /* Bumper zone. */
- movl $0, (%edx)
- movl $0, 4(%edx)
- movl $0, 8(%edx)
- movl $0, 12(%edx)
- /* Program "global" parameters to move to the parameter stack, or pre-allocate. */
- subl $7*4, %edx /* Allocate all the parameters. */
- /* %esi 6 -- Pointer to main's first argument, argc. */
- movl %esi, 6*4(%edx) /* Copy */
- /* -48(%ebp) 5 -- argv */
- movl -48(%ebp), %eax /* Copy */
- movl %eax, 5*4(%edx)
- /* -52(%ebp) 4 -- exit code, just allocate */
- /* -28(%ebp) 3 -- parseP, just allocate */
- /* -20(%ebp) 2 -- n1, just allocate */
- /* -24(%ebp) 1 -- n2, just allocate */
- /* -32(%ebp) 0 -- divisor, just allocate */
- movl %ebp, (%esp) /* Keep %ebp for restoring later. ("old frame pointer") */
- /* Set up %ebp as the parameter stack pointer: */
- movl %edx, %ebp
- /* From here to .L11, do NOT reference %esp for parameters or variables! */
- movl 6*4(%ebp), %eax /* argc (first arg of main) */
- cmpl $3, %eax
- je .L9
- subl $2*4, %ebp /* allocate, lazily */
- movl 7*4(%ebp), %eax /* argv */
- movl (%eax), %eax /* argv[ 0 ] */
- movl %eax, 1*4(%ebp)
- leal .LC0@GOTOFF(%ebx), %eax
- movl %eax, (%ebp)
- movl $printf@PLT, %eax
- call shim2p
- leal .LC1@GOTOFF(%ebx), %eax
- movl %eax, (%ebp)
- movl $puts@PLT, %eax
- call shim1p
- addl $2*4, %ebp /* deallocate, lazily */
- movl $1, 4*4(%ebp) /* EXIT_FAILURE */
- jmp .L11
- .L9:
- subl $3*4, %ebp /* allocate */
- movl 8*4(%ebp), %eax /* argv */
- addl $4, %eax
- movl (%eax), %edx /* arg[ 1 ] */
- movl $0, 2*4(%ebp)
- leal 6*4(%ebp), %eax /* &parseP */
- movl %eax, 1*4(%ebp)
- movl %edx, (%ebp) /* arg[ 1 ] */
- movl $strtoul@PLT, %eax
- call shim3p
- movl %eax, 5*4(%ebp) /* n1 */
- addl $3*4, %ebp /* deallocate */
- movl 5*4(%ebp), %eax /* argv */
- addl $4, %eax
- movl (%eax), %edx /* argv[ 1 ] */
- movl 3*4(%ebp), %eax /* parseP */
- cmpl %eax, %edx
- jae .L12
- subl $3*4, %ebp /* allocate */
- movl 8*4(%ebp), %eax /* argv */
- addl $8, %eax
- movl (%eax), %edx /* argv[ 1 ] */
- movl $0, 2*4(%ebp)
- leal 6*4(%ebp), %eax /* &parseP */
- movl %eax, 1*4(%ebp)
- movl %edx, (%ebp) /* argv[ 1 ] */
- movl $strtoul@PLT, %eax
- call shim3p
- movl %eax, 4*4(%ebp) /* n2 */
- addl $3*4, %ebp /* deallocate */
- movl 5*4(%ebp), %eax /* argv */
- addl $8, %eax
- movl (%eax), %edx /* argv[ 1 ] */
- movl 3*4(%ebp), %eax /* parseP */
- cmpl %eax, %edx
- jae .L14
- /* Make the call to gcd() */
- subl $2*4, %ebp /* allocate parameters */
- movl 3*4(%ebp), %eax /* n2 */
- movl %eax, 1*4(%ebp)
- movl 4*4(%ebp), %eax /* n1 */
- movl %eax, (%ebp)
- call gcd /* No shim! (Yay!) */
- addl $2*4, %ebp
- /* Recover the return value. */
- movl %eax, (%ebp) /* divisor */
- subl 5*4, %ebp /* allocate, lazily */
- movl 5*4(%ebp), %eax /* divisor */
- movl %eax, 1*4(%ebp)
- leal .LC2@GOTOFF(%ebx), %eax
- movl %eax, (%ebp)
- movl $printf@PLT, %eax
- call shim2p
- movl 6*4(%ebp), %edx /* n2 */
- movl %edx, %eax
- sarl $31, %edx
- idivl 5*4(%ebp) /* divisor */
- movl %eax, %ecx
- movl 7*4(%ebp), %edx /* n1 */
- movl %edx, %eax
- sarl $31, %edx
- idivl 5*4(%ebp) /* divisor */
- movl %ecx, 4*4(%ebp) /* n2 / divisor */
- movl %eax, 3*4(%ebp) /* n1 / divisor */
- movl 6*4(%ebp), %eax /* n2 */
- movl %eax, 2*4(%ebp)
- movl 7*4(%ebp), %eax /* n1 */
- movl %eax, 1*4(%ebp)
- leal .LC3@GOTOFF(%ebx), %eax
- movl %eax, (%ebp)
- movl $printf@PLT, %eax
- call shim5p
- addl 5*4, %ebp /* deallocate, lazily */
- movl $0, 4*4(%ebp) /* EXIT_SUCCESS */
- jmp .L11
- .L14:
- subl 2*4, %ebp /* allocate */
- movl 7*4(%ebp), %eax /* argv */
- addl $8, %eax
- movl (%eax), %eax /* argv[ 2 ] */
- movl %eax, 1*4(%ebp)
- leal .LC4@GOTOFF(%ebx), %eax
- movl %eax, (%ebp)
- movl $printf@PLT, %eax
- call shim2p
- addl 2*4, %ebp /* deallocate */
- jmp .L16
- .L12:
- subl 2*4, %ebp /* allocate */
- movl 7*4(%ebp), %eax /* argv */
- addl $4, %eax
- movl (%eax), %eax /* argv[ 1 ] */
- movl %eax, 1*4(%ebp)
- leal .LC4@GOTOFF(%ebx), %eax
- movl %eax, (%ebp)
- movl $printf@PLT, %eax
- call shim2p
- addl 2*4, %ebp /* deallocate */
- .L16:
- movl $1, 4*4(%ebp) /* EXIT_FAILURE */
- .L11:
- movl 4*4(%ebp), %eax /* But the exit code is on the parameter stack. */
- movl (%esp), %ebp /* restore ebp, drop the parameter stack. */
- movl %eax, -52(%ebp) /* exit code in interleaved stack */
- /* Forgot to free in gcddummy.c.
- movl 4(%esp), %eax
- movl %eax, (%esp)
- call free@PLT
- */
- /* But we mmap()ed it instead. */
- movl $65536, 4(%esp) /* requested length */
- movl -36(%ebp), %eax /* pstack */
- movl %eax, (%esp)
- call munmap@PLT
- movl -52(%ebp), %eax /* exit code to exit with */
- myexit:
- movl -16(%ebp), %edx
- xorl __guard_local@GOTOFF(%ebx), %edx
- je .L18
- /* Trap a bad return address. */
- leal .LSSH0@GOTOFF(%ebx), %eax /* walk on the exit code */
- movl %eax, (%esp)
- call __stack_smash_handler@PLT /* catch smash attempt */
- /* Valid exit: */
- .L18:
- addl $60, %esp
- popl %ecx
- popl %ebx
- popl %esi
- popl %ebp
- leal -4(%ecx), %esp
- ret
- .size main, .-main
- .section .gnu.linkonce.t.__i686.get_pc_thunk.bx,"ax",@progbits
- .globl __i686.get_pc_thunk.bx
- .hidden __i686.get_pc_thunk.bx
- .type __i686.get_pc_thunk.bx, @function
- __i686.get_pc_thunk.bx:
- movl (%esp), %ebx
- ret