i686 (AMD Duron 800 MHz) idiv opcode needs cdq: Why?

From: August Derleth (see_at_sig.now)
Date: 01/20/04


Date: Tue, 20 Jan 2004 22:54:21 +0000 (UTC)

When writing a small subroutine in i686 assembly for Linux (Red Hat 8.0,
kernel version 2.4.18-14), I came upon a bizarre problem: The div opcode
would cause my program to die after having failed to catch a floating
point exception. I replaced the div with an idiv, and nothing changed.
The problem stymied me completely until I chanced upon an assembly
source my C compiler (gcc 3.2) emitted: The idiv opcode in the emitted
assembly was preceded by a cdq (Convert Doubleword to Quadword) opcode,
which sign-extends eax into edx:eax. As the compiled C program ran
flawlessly, I dumped a cdq opcode into my own program. Problem solved.

But that's simply human-see, human-do. I want to understand why the idiv
opcode requires the cdq opcode, and whether this is a flaw in my
hardware (800 MHz AMD Duron), my OS, my assembler (nasm 0.98.34), or
anything else.

# For reference, here's a small shell script (Bourne-compatible) that
# will create two nasm assembly source files which produce two programs
# which demonstrate the problem and the solution, in addition to one
# Makefile. I'd be interested to know of any hardware/software
# combination that runs lose.asm without any problems, or that fails to
# run win.asm.
cat << CUT > lose.asm
    ;; A small program to divide two signed dwords
    ;; using the idiv opcode unsuccessfully
    ;; (without the cdq opcode).
section .text

global main
main: push ebp
    mov ebp, esp
    mov dword eax, 130
    mov dword ecx, 5
    idiv ecx ; We get floating point exception.
    mov esp, ebp
    pop ebp
    ret ; We never return. Exception kills us.
    ;; Final value of eax is 136. Meaningful?
CUT
cat << CUT2 > win.asm
    ;; A small program to divide two signed dwords
    ;; using the idiv opcode successfully (via the
    ;; cdq opcode).
section .text

global main
main: push ebp
    mov ebp, esp
    mov dword eax, 130
    mov dword ecx, 5
    cdq ; sex edx:eax, eax
    idiv ecx
    mov esp, ebp
    pop ebp
    ret ; We return eax == 26
CUT2
cat << EOF > Makefile
cc = gcc
# Older Linux systems might prefer a.out as a format.
fmt = elf

win: win.o
        $(cc) win.o -o win
win.o: win.asm
        nasm -f $(fmt) win.asm
lose: lose.o
        $(cc) lose.o -o lose
lose.o: lose.asm
        nasm -f $(fmt) lose.asm
EOF

-- 
My address is yvoregnevna gjragl-guerr gjb-gubhfnaq guerr ng lnubb qbg pbz
Note: Rot13 and convert spelled-out numbers to numerical equivalents.


Relevant Pages

  • Re: translating Python to Assembler
    ... The 54 is an assembler opcode for push and the sp is ... assembler and don't want to learn anything about Python). ... the opcodes for each instruction. ...
    (comp.lang.python)
  • Re: from elsewhere, an assembler
    ... I also like how it is fairly light on memory and windows resources, ... I hope you try to write an assembler! ... opcode during assembly). ... I have some experience writing dynamic compilers for script ...
    (alt.lang.asm)
  • Re: assembly in Platform Builder
    ... and write your code the same way with the same directives. ... > BL func ... > opcode: kxarm.h ... >> kxarm.h goes in the assembler file, ...
    (microsoft.public.windowsce.platbuilder)
  • Re: [OT] PostLisp, a language experiment
    ... As for modularity, I ... A typical case is an assembler. ... Forth assemblers have typically a word that handles an opcode. ... Albert van der Horst,Oranjestr 8,3511 RA UTRECHT,THE NETHERLANDS ...
    (comp.lang.lisp)