Path: utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!sun-barr!olivea!apple!netcom!mcmahan From: mcmahan@netcom.UUCP (Dave Mc Mahan) Newsgroups: comp.sys.amiga.tech Subject: Re: Code generation Message-ID: <14827@netcom.UUCP> Date: 16 Oct 90 03:17:14 GMT References: <512@cbmger.UUCP> Organization: Dave McMahan @ NetCom Services Lines: 59 In a previous article, peterk@cbmger.UUCP (Peter Kittel GERMANY) writes: >Again that old theme '(self) modifying code': When I think about it, >there HAS to be a clean way. How else could a debugger or a machine >language monitor work? I must be able to poke some bytes in the >memory to other values and then take this as code or data just as >I want, without LoadSeg()ing this everytime. Debuggers on modern (68000) CPUs generally use one of two methods for tracing a program. The first will ALWAYS work, but is slow. The second runs at full speed (until the desired breakpoint is hit) but requires the code being debugged to be in RAM. 1. The debugger operates as kind of a micro-OperatingSystem. When you tell it to go, it sets the TRACE bit of the 68000. This is a hardware debug mode that Motorola thoughfully included on all CPUs. Before every instruction is executed, the CPU traps back to a special interrupt vector (the TRACE vector) and enters Supervisor mode so that no other TRACE interrupts will occur. The TRACE vector points to the start of the debugger routine that does whatever the debugger wants to do, usually decode the instruction into the assembly mneumonic and dump all the registers for the user to see. When the debugger has finished whatever it intended to do, it does an RTE instruction which causes the target opcode to be executed just like normal. When the next instruction after that is about to be executed, the TRACE interrupt is again asserted by the CPU and the whole process repeats. This method works even with code in ROM (and with a ROMed debugger, if you have one) and only requires some RAM to manage the debugger stack and local variables. Since it interrupts every instruction, the execution time is noticeably affected. 2. The second method used works only with debug code in RAM. The debugger is instructed by the user to replace the instruction at the desired address with an illegal instruction (usually, the ILLEGAL instruction itself! This is a real op-code, haveing a value of 0x8AFC. Look it up!) The debugger then replaces the location in the interrupt vector table where the ILLEGAL instruction would vector to and provides it's own internal vector for processing the breakpoint (The exception vector table must be in RAM also for this to work). The debugger then starts execution at full speed wherever the programmer tells it to. When it hits the ILLEGAL instruction, the CPU vectors to the proper spot in the debugger to handle the breakpoint. This method allows you to run at full speed, but has the side effect of never stopping if you put your breakpoint at the wrong place and that code doesn't get executed. Generally, the programmer places two breakpoints so that he can trap at the desired point when it hits, but can always force the program to hit the other one if he screwed up and didn't put it in the right spot or if the program is doing something he didn't expect (which is why he is probably debugging with a monitor in the first place). >Simply put: How does LoadSeg() do it???? Do what? I have never used LoadSeg(), but my book says that it just loads a module into memory and links the scattered segments together. All it does is load. >Best regards, Dr. Peter Kittel -dave