|
Prev: stricmp
Next: Killing Explorer
From: Tom on 11 Mar 2005 08:02 Hello, For some time now I have been learning assembly on my own using Webster. So far I have managed to build a small paper-and-pencil uP and read/comprehend most of the material from the 16-bit DOS version of AoA (I understand DOS is obsolete, but I have found it simpler to start with, hope to do better in the future). Would you be kind enough as to help me clarify the following points (regarding real mode programming): 1. Why do segment registers hold segments' paragraph numbers rather than their absolute addresses? 2. In Chapter 6 of AoA (The instruction set, 6.11.1 Simple arithmetic I) Mr. Hyde gives an example of code in which he declares a procedure MAIN, which is duly terminated with "Main endp". What does the second "end Main" expression stand for? Why is this procedure not called? Or is it? Thank you very much for all kind replies. Kindest regards, Tom
From: NoDot on 11 Mar 2005 08:23 Tom wrote: > Hello, Greetings > 1. Why do segment registers hold segments' paragraph numbers rather > than their absolute addresses? It's how real mode operates. Intel chose this mode because it's an easy way to extend the memory to 1M without much complexity. > 2. In Chapter 6 of AoA (The instruction set, 6.11.1 Simple arithmetic > I) Mr. Hyde gives an example of code in which he declares a procedure > MAIN, which is duly terminated with "Main endp". What does the second > "end Main" expression stand for? Why is this procedure not called? Or > is it? I haven't read the 16-bit edition for a long time. Randall'll have to answer you on this one. > Thank you very much for all kind replies. Kind? Not here, unfortunately. At comp.lang.asm.x86, they're kind. > Kindest regards, > Tom -- The above was written by NoDot. Visit the Website of NoDot: <www.geocities.com/nodot1989/>
From: Herman Dullink on 11 Mar 2005 12:12 > 1. Why do segment registers hold segments' paragraph numbers rather > than their absolute addresses? This is Intel's first attempt to break the 64KB limit of a 16-bit CPU. Using paragraph addresses expands the total addressable space to 1MB. This allows definition of several variable sized segments. Because of lack of protection, it's possible to address outside the segment... This is only the case on 8086 and compatible CPUs, and in Real Mode on 80286 and compatible CPUs. In protected mode, segment registers hold an index in a segment descriptor table, which not only hold a base (absolute) address, but also its size (which is checked for every access) and privileges (level,read/write/execute). > What does the second > "end Main" expression stand for? Why is this procedure not called? Or > is it? The "end" is to tell the assembler that this is the end of the source code. The "Main" is to set the entry point. The linker will put this address in the header of the executable file. DOS will then execute from this address when this file is executed. If e.g. you would put a 2nd procedure in this source file (MyMain) and use the name of that 2nd procedure after end, then that 2nd procedure is run, and not "Main". H
From: Frank Kotler on 11 Mar 2005 15:08 Tom wrote: > > Hello, > For some time now I have been learning assembly on my own using > Webster. So far I have managed to build a small paper-and-pencil uP and > read/comprehend most of the material from the 16-bit DOS version of AoA > (I understand DOS is obsolete, but I have found it simpler to start > with, hope to do better in the future). I agree. You'll find some people feel that you shouldn't "waste" any time at all learning dos. I'd agree that it isn't worthwhile learning "dos", per se, in any depth, but I agree with you that it's "simpler" to interface with dos than with Windows or Linux. Linux has an "int 80h" interface - similar to the dos "int 21h" interface, but Windows requires calling a "Dynamically Linked Library". Easy enough to *do*, but harder to understand what you're *doing* (IMO). 32-bit programming, in itself, is *easier* than 16-bit programming - no worries about segments, and the addressing modes are much more flexible. Once you feel ready to make the switch (I'd learn how "call" and "ret" work - how to use the stack to pass parameters, and keep the stack "sane"), I think you'll like 32-bit programming... so don't waste *too* much time with dos! > Would you be kind enough as to help me clarify the following points > (regarding real mode programming): > > 1. Why do segment registers hold segments' paragraph numbers rather > than their absolute addresses? Funny you should ask... (see the thread about ".model" in Tasm). It's either: 1) Because that's the chip the market *demanded* (at *that* time). Easy "upgrade path" for 8080 code, and ability to use more than 64k without "wasting" much memory. (my theory) Or: 2) Intel was really stupid. (Beth's theory) In any case, I think we agree that it wouldn't be a sensible way to design a chip *now*. For purposes of *using* it, rather than trying to improve on Intel's design, just assume "that's the way it is". > 2. In Chapter 6 of AoA (The instruction set, 6.11.1 Simple arithmetic > I) Mr. Hyde gives an example of code in which he declares a procedure > MAIN, which is duly terminated with "Main endp". What does the second > "end Main" expression stand for? It isn't really "second" - "end" is different from "ends". "end" tells Masm that your code ends - anything after that is ignored - *and* the label after "end" defines where the entrypoint to the code is - this example probably doesn't do it, but you could put subroutines *before* your "Main", and execution would still start at "Main:"... For comparison - a ".com" file always starts at the beginning of your code. Other assemblers indicate the entrypoint differently - Nasm, for example, uses "..start:" and doesn't use "end" or "ends" at all. > Why is this procedure not called? Or > is it? No, it's not. Personally, I think "Main" is a potentially confusing name to use, if it isn't a "C-style" main - that is, called (so a "ret" or "retf" will exit it), and with argc, argv, and envp on the stack. That isn't the situation with an asm program unless you write the code to do it. Or... you can write an asm file using "main" (probably have to be "_main", actually), assemble it to an .obj file, and use a C compiler to link it... *with* C startup code. In this case, "main" needs to be named "main". Otherwise, *I'd* call it something else. > Thank you very much for all kind replies. You're welcome. Thank *you* for the on-topic question! Ignore any "less-than-kind" replies you get, and ignore any newbie twirps who advise you to take your questions to clax! We *do* discuss assembly language around here... sometimes... Best, Frank
From: Herbert Kleebauer on 12 Mar 2005 06:23
Frank Kotler wrote:> > 32-bit programming, in itself, is *easier* than 16-bit > programming - no worries about segments, and the addressing > modes are much more flexible. Once you feel ready to make > the switch (I'd learn how "call" and "ret" work - how to use > the stack to pass parameters, and keep the stack "sane"), I > think you'll like 32-bit programming... so don't waste *too* > much time with dos! It is not fair to tell this old but wrong fairytale to newcomer. DOS doesn't restrict you in any way to to 16 bit operand size or 16 bit addressing modes and you are also not bound to real/v86 mode. For learning assembly programming, there is nearly no difference between using DOS or Windows: in DOS you are restricted in the amount of usable memory (but this really doesn't matter for learning assembly programming) and there is much less overhead in DOS than in Windows (executable file format, OS API) which makes it much easier to start assembly programming in DOS. As an example a program which calculates the md5 hash for stdin. There is no way to tell if this is a Win32 or a DOS program. It can be assembled for both, all you have to do is to insert the proper getc, putc and exit functions. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; md5.mac ;; ;; calculate md5 hash for stdin (see RFC 1321) ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; bclr.w #10,sr ; clear direction flag for auto increment eor.l r4,r4 ; low bit count eor.l r5,r5 ; high bit count _11: move.l #64,r2 ; read 64 bytes move.l #buf,r6 ; pointer to 64 byte buffer _10: bsr.l getc ; read char from stdin move.b r0,(r6)+-{s1} ; store in buffer and increment pointer cmpq.l #-1,r0 ; end of file beq.b _20 ; yes addq.l #1,r4 ; incr total number of read bytes addcq.l #0,r5 dbf.l r2,_10 ; repeat until 64 bytes read bsr.l md5 ; update md5 hash for 64 bytes read br.b _11 ; next 64 byte block _20: dsl.l #3,r5<r4 ; total number of read bits lsl.l #3,r4 move.b #$80,-1.b(r6) ; replace EOF by $80 _31: move.l r6,-(sp) ; save pointer _30: cmp.l #buf+63,r6 bhi.b _32 move.b #0,(r6) ; fill rest of buffer with 0 inc.l r6 br.b _30 _32: move.l (sp)+,r6 cmp.l #buf+56,r6 ; 8 bytes free in buffer? bls.b _40 ; yes bsr.l md5 ; update md5 hash for 64 bytes in buffer move.l #buf,r6 ; need a fresh 64 byte block br.b _31 _40: move.l r4,buf+56 ; insert bit count in last 8 bytes move.l r5,buf+60 bsr.l md5 ; update md5 hash for 64 bytes in buffer move.l #a,r5 ; pointer to hash value move.l #16,r2 ; 16 byte hash _60: move.b (r5),r0 ; next byte of hash lsr.b #4,r0 ; upper nippel bsr.l _70 ; convert to hex and output move.b (r5)+-,r0 ; get byte again and inc pointer and.b #$0f,r0 ; lower nippel bsr.l _70 ; convert to hex and output dbf.l r2,_60 ; all 16 byte done? bsr.l exit _70: add.b #'0',r0 ; convert to ascii cmp.b #'9',r0 ; lower same '9' bls.b _50 ; yes, then ok add.b #'a'-'9'-1,r0 ; no, convert to a-f _50: bsr.l putc rts.l md5: ; this is a 1:1 implementation of the code in RFC 1321 ; so no documentation is given here move.l r5,-(sp) ; don't modify r4 and r5 move.l a,r0 move.l r0,aa move.l b,r0 move.l r0,bb move.l c,r0 move.l r0,cc move.l d,r0 move.l r0,dd move.l #a,r5 eor.l r3,r3 _10: cmp.b #15,r3 bhi.b _20 move.l 4.b(r5),r0 move.l r0,r1 and.l 8.b(r5),r1 not.l r0 and.l 12.b(r5),r0 or.l r1,r0 br.b _50 _20: cmp.b #31,r3 bhi.b _30 move.l 12.b(r5),r0 move.l r0,r1 and.l 4.b(r5),r1 not.l r0 and.l 8.b(r5),r0 or.l r1,r0 br.b _50 _30: cmp.b #47,r3 bhi.b _40 move.l 4.b(r5),r0 eor.l 8.b(r5),r0 eor.l 12.b(r5),r0 br.b _50 _40: move.l 12.b(r5),r0 not.l r0 or.l 4.b(r5),r0 eor.l 8.b(r5),r0 _50: add.l (r5),r0 movu.bl index(r3),r6 add.l buf(r6*4),r0 add.l sin(r3*4),r0 move.b shift(r3),r2 rol.l r2,r0 add.l 4.b(r5),r0 move.l r0,(r5) move.l r0,16.b(r5) subq.l #4,r5 cmp.l #b0,r5 bhs.b _60 addq.l #16,r5 _60: inc.b r3 cmp.b #64,r3 blo.l _10 move.l aa,r0 add.l r0,a add.l r0,a0 move.l bb,r0 add.l r0,b add.l r0,b0 move.l cc,r0 add.l r0,c add.l r0,c0 move.l dd,r0 add.l r0,d add.l r0,d0 move.l (sp)+,r5 rts.l b0: dc.b $89,$ab,$cd,$ef c0: dc.b $fe,$dc,$ba,$98 d0: dc.b $76,$54,$32,$10 a: dc.b $01,$23,$45,$67 b: dc.b $89,$ab,$cd,$ef c: dc.b $fe,$dc,$ba,$98 d: dc.b $76,$54,$32,$10 a0: dc.b $01,$23,$45,$67 index: dc.b 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15 dc.b 1, 6,11, 0, 5,10,15, 4, 9,14, 3, 8,13, 2, 7,12 dc.b 5, 8,11,14, 1, 4, 7,10,13, 0, 3, 6, 9,12,15, 2 dc.b 0, 7,14, 5,12, 3,10, 1, 8,15, 6,13, 4,11, 2, 9 shift: dc.b 7,12,17,22, 7,12,17,22, 7,12,17,22, 7,12,17,22 dc.b 5, 9,14,20, 5, 9,14,20, 5, 9,14,20, 5, 9,14,20 dc.b 4,11,16,23, 4,11,16,23, 4,11,16,23, 4,11,16,23 dc.b 6,10,15,21, 6,10,15,21, 6,10,15,21, 6,10,15,21 sin: dc.l $d76aa478, $e8c7b756, $242070db, $c1bdceee, $f57c0faf, $4787c62a dc.l $a8304613, $fd469501, $698098d8, $8b44f7af, $ffff5bb1, $895cd7be dc.l $6b901122, $fd987193, $a679438e, $49b40821, $f61e2562, $c040b340 dc.l $265e5a51, $e9b6c7aa, $d62f105d, $02441453, $d8a1e681, $e7d3fbc8 dc.l $21e1cde6, $c33707d6, $f4d50d87, $455a14ed, $a9e3e905, $fcefa3f8 dc.l $676f02d9, $8d2a4c8a, $fffa3942, $8771f681, $6d9d6122, $fde5380c dc.l $a4beea44, $4bdecfa9, $f6bb4b60, $bebfbc70, $289b7ec6, $eaa127fa dc.l $d4ef3085, $04881d05, $d9d4d039, $e6db99e5, $1fa27cf8, $c4ac5665 dc.l $f4292244, $432aff97, $ab9423a7, $fc93a039, $655b59c3, $8f0ccc92 dc.l $ffeff47d, $85845dd1, $6fa87e4f, $fe2ce6e0, $a3014314, $4e0811a1 dc.l $f7537e82, $bd3af235, $2ad7d2bb, $eb86d391 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; unitialized data ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; aa: blk.l 1 bb: blk.l 1 cc: blk.l 1 dd: blk.l 1 buf: blk.b 64 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; end of md5.mac ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |