Dear DDJ,
I enjoyed Rob Moore's article on "Mapping DOS Memory Allocation" (November 1988) very much; it made a lot of sense. I did have some problems converting it over to Microsoft C, though. The one change I discovered was that <dos.h> in Microsoft C does not contain a MK_FP (segment, offset) macro, so I borrowed the macro from a friend who uses Turbo C. The macro left shifts the segment into the next word and ors the offset in.
This one macro, however, was not enough. I am not convinced that my program, called ptrmcb, is accurately finding memory control blocks. The first five bytes of the first memory-control block found are: 0973:0000 4D 08 00 08 02. Referring to the structure of "struct mcb": chain = 'M'; pid = 2048; psize = 2050.
I am using QuickC and MSC 4.0 with MS-DOS 3.3. Example 1 shows a run of both mcb and mapmem. Any thoughts on completing the conversion from Turbo C to Microsoft C would be appreciated.
Bruce Koivu
Orlando, Fla.
PSP bytes owner command line hooked vectors ---------------------------------------------------------------------- 0008 8320 N/A 0B7D 4176 N/A 22 24 2E 0C99 603760 free ====================================================================== MCB MCB ID PID MB PARENT ENV OWNER NO. SEG SIZE BLK? ---------------------------------------------------------------------- 01 0973 M 0800 28704 068C N 02 0973 0007 7808 022B N UNKNOWN OWNER ======================================================================
Robert responds:
You are correct that Microsoft C (MSC) provides no macro MK_FP (seg,off) to construct a far pointer composed of segment seg and offset off. Other DDJ readers have pointed this out to me, notably Ron Sonntag (of Analytical Software Consulting in Seattle, Wash.), who found it necessary to replace the macro FP_SEG with the Turbo C version and make other related macro definition adjustments when converting MCB.C to run under MSC 5.1. (I won't give any further details because I currently do not have access to a copy of MSC and cannot personally vouch for the results.)
Mr. Koivu's erroneous output from my MCB program is almost certainly due to compilation of the program with a compiler option set to word alignment. My program will not execute properly under any C compiler unless byte alignment is used. I worked out the examples after reader Edward Rippy of Oakland, Calif. informed me of similar problems he encountered when he tried word alignment under Turco C.
When compiled under byte alignment (this is the default in Turbo C), MCB.EXE reports the results, shown in Example 2, when invoked on my current system (true blue IBM PC running under PC-DOS 3.2).
=========================================================================== MCB MCB ID PID MB PARENT ENV OWNER NO. SEG SIZE BLK? --------------------------------------------------------------------------- 01 0974 M 0008 134768 0291 N IBMDOS.COM/MSDOS.SYS 02 2A5C M 2A5D 3120 2A5D N COMMAND.COM COPY #1 03 2B20 M 2A5D 160 2A5D Y COMMAND.COM COPY #1 . . . (22 MCBs not relevant to discussion omitted) . . . 25 331B M 3327 160 2A5D Y C:\UTIL\MCB.EXE 26 3326 M 3327 71264 2A5D N C:\UTIL\MCB.EXE 27 448D Z 0000 374560 F000 N FREE MEMORY CONTROL BLOCK ===========================================================================
When I compile under word alignment (Options/Compiler/Code Generation/Alignment Word in the Turbo C integrated environment or the command line-a option) and run the new MCB.EXE I get the results that are shown in Example 3.
================================================================ MCB MCB ID PID MB PARENT ENV OWNER NO. SEG SIZE BLK? ---------------------------------------------------------------- 01 0974 M E700 512 FF7E N ************* 02 0999 * BCDO 11568 0720 N UNKNOWN OWNER ================================================================
Note: All characters marked * (asterisk) are various nonprintable characters, which confirms all the more that there is a problem.
This latter mess is similar to that reported by reader Koivu. Let me explain what has gone wrong. The relevant contents of the first MCB located at 0974:0000 (hex) in my case are 4D 08 00 E7 20 00 determined by using DOS DEBUG. A pointer to struct MCB is used as a template to overlay and retrieve the contents of the MCBs as they already exist in memory. From my MCB.C listing, struct MCB is defined as:
struct MCB
{
char chain;
unsigned pid;
unsigned psize;
char unused[11]'
};With byte alignment, the compiler does not adjust user-defined structures, so, if a structure of this type overlays the first MCB in memory we get:
chain = 4D ('M'interpreted as char)
pid = 08 00 (0x0008 interpreted
as unsigned)
psize = E7 20 (0x20EF interpreted
as unsigned)This occurs because the contents of offset 0 are assigned to chain, offsets 1 and 2 to pid, and offsets 3 and 4 to psize, which you would expect upon examination of the definition of struct MCB. (When interpreting the results remember that Intel processors use "backwords" storage.)
Furthermore, the size of struct MCB is 0x10 (16 decimal), so each unit increment of a pointer to such a structure (ptrmcb in my published MCB.C listing) increases the address of the pointer by 0x10 bytes. The next MCB is thus located at 0x974:0 + 0x20EF.* 0x10 + 1 = 0x2A5C:0 and agrees with MCB NO. 02 in Example 2.
With word alignment, the compiler generates code to start each field of a structure on an even address boundary, which provides for quicker execution on the 80286 and 80386 processors. Usually such adjustments by the compiler make no difference. However, in a case where a structure is used as a template (i.e., used to overlay and retrieve existing data in memory written by some other process), such compiler adjustments are generally unwanted. Let's see what goes wrong in the case at hand.
With word alignment we get
chain = 4D ('M' interpreted as char)
pid = 00 E7 (0x0008 interpreted
as unsigned)
psize = 20 00 (0x20 interpreted
as unsigned)
This is because the compiler has padded the byte after the chain field with an extra byte so that the remaining structure fields pid, psize, and unused[11] all start on word boundaries. The unused[11] field is also padded on the end with an extra byte so that the structure holds an even number of bytes (0x12 = 18 in this case). The vales of pid and psize are then read from the contents of offsets 2-3 and 4-5, respectively. You can imagine the problems this creates since the proper values are contained in offsets 1-2 and 3-4 instead. Furthermore, each increment of a pointer to this word aligned structure increases the pointer's address by 0x12 bytes, not by 0x10. It is no wonder the main logic of the MCB program (chain successively from the first to the last MCB) is immediately derailed leading to the print out of garbage.Reader Sonntag informs me that the statement #pragma pac(1) (an MSC compiler directive) placed at the top of the MCB.C source file will cause MSC 5.1 to compile with byte alignment. I would imagine that an equivalent command line switch (for MSC) or a menu selection (for Quick C) exists to accomplish the same thing. In any case, I strongly recommend that Codeview be used to step through MCB.EXE to drive home the ideas I have presented.
Dear DDJ,
Tandy Corp. offers a 20-Mbyte hard disk for its mode 1400 LT portable computer, which I eagerly purchased hoping to finally have a gem of a machine. But alas ... problems with the power supply destroyed my aspirations.
It seems to me that the AC power adapter supplied with the 1400 LT does not produce enough current to sustain the 1400 LT and cannot operate the computer (and hard disk) on AC only. My question is as follows: Is it possible to substitute the AC power adapters supplied with the unit with a more powerful one? If so, how can I obtain or build one?
The following information could possibly be of help in solving my problem: Tandy AC adapter (supplied with unit); class 2 transformer; input 120V AC, 60Hz, 20W; and output 15V DC, 700mA. Also, I have a LiteDrive-II hard disk subsystem by CMS Enhancements.
A solution to this problem would greatly benefit me and my fellow 1400 LT users.
Wilberto Garcia
456 Beach 63rd St.
Arverne, NY 11692
Dear DDJ,
I am writing the first letter to a magazine that I have ever written in my (47 years) life, in response to the recent series by Al Stevens. In a nutshell, I think the series has been fantastic!
I started programming 25 years ago in Cobol; I have written in Assembler, Fortran, Basic, Easycoder, and Autocoder, and I have thoroughly enjoyed the "C Column." As a youngster I used to enjoy saving my nickels and buying Popular Mechanics magazine (for 25 cents), taking it home, building something based on an article, and then showing it off to my family and friends. Thanks to Al Stevens' column, I can enjoy the same pleasure and satisfaction that I did so many years ago.
I am a programmer: I write computer software (for a firm in Silicon Valley), and I still enjoy tinkering. Thanks to Al's great column, I look forward to Dr. Dobb's Journal every month like I used to look forward to the latest Popular Mechanics.
Don't let the flak from the Microsoft C folks derail a great project. The serious programmer doesn't want to hear the politics about which C compiler is better or why. Let the Dvoraks handle that, and keep Al Stevens busy with the projects that are so much fun and so rewarding. Thanks a million!
Richard M. Linder
Los Gatos, Calif.
Dear DDJ,
I take umbrage with your (Kent Porter's) complaints on the wordiness of Modula-2 library procedures. Even the most primitive of text editors (and the JPI environment) will perform global substitutions; thus, one need only type some small acronym until one is finished and replace them later. Actually, I tend to place reassignments such as
CONST WRiteChar = IO.WrChar;
in my modules because I personally find the abbreviation "Wr" somewhat damaging to the eye.
The aspect of Modula-2 that I take dearest to heart is the necessity of explicitly stating the location of the procedures used. In contrast, C will freely accept IOUs in lieu of code, and it's not until the linker hauls you up before the bench that you know something is missing. Modula-2 demands cash on the barrelhead (or at least in the definition modules), or one goes nowhere.
The notion of type transfer allows you to do as much damage in this language as in C. Simply assign an arbitrary code location to a PROC-type variable and then call it to see this. Perhaps one could convert this into some sort of inline code for JPI (by assigning the location of a constant aggregate), but it doesn't seem worth it, for their assembler meshes so nicely with their compiler.
I hope your successor (Jeff Duntemann) will not forgo Modula-2 for Turbo Pascal.
John O. Goyo
Copyright © 1989, Dr. Dobb's Journal