Solved

ASM routine needs BEGIN/END, else it won't work correctly??

Posted on 1998-10-27
13
250 Views
Last Modified: 2013-11-22
Hi!

Recently, I asked a question how to read/write I/O ports under Win95. I got the answer, and I tried to improve the necessary GetPort/SetPort routines to be pure ASM routines.

While doing this, I ran into a strange problem. The first procedure in the following code scrap DOES NOT WORK! The 2nd DOES indeed. According to Delphi3 Help, there is no (syntax) problem with the first solution (as far as I understand it). Can you tell me why the first procedure does not work (stepping through it tells me the value of the 'Value' parameter is wrong, but WHY?)??

What I need is a modification to the first routine, but it should still remain a *pure* ASM routine (without BEGIN and END words!).

----->8----- SNIP

{ ***** MY asm routine ***** }
procedure SetPort(Address: Word; Value: Byte);
asm
  mov  dx,Address
  mov  al,Value
  out  dx,al
end;

{ ***** alternative routine ***** }
procedure SetPort(Address: Word; Value: Byte);
begin  <---- only difference
asm
  mov  dx,Address
  mov  al,Value
  out  dx,al
end;
end;   <---- only difference

----->8----- SNIP

nova666.
0
Comment
Question by:nova666
  • 5
  • 4
  • 2
  • +2
13 Comments
 
LVL 4

Expert Comment

by:dwwang
Comment Utility
I think begin..end is needed by all functions and procedures due to pascal syntax. I don't feel it strange at all.
0
 
LVL 1

Author Comment

by:nova666
Comment Utility
NO! BEGIN/END is NOT needed here. The difference is that when I use BEGIN/ASM/END/END, the compiler generates extra code for the procedure/function, and when I only use ASM/END (like above), it doesn't (this is called an 'assembler procedure/function'). But I don't exactly know what the differences are in the generated code, so there's the problem...

I noticed that turning Optimization on/off doesn't help anything, and I noticed that the registers already have some values of the parameters at the asm procedure's start:

Value    is in  DL
Address  is in  AX

Maybe that's the difference: when I use an assember proc/func, the compiler doesn't generate local variables for the parameters, but puts them into registers. BUT I AM NOT SURE IF THIS IS RIGHT, and I don't want to speculate about the registers' contents, because this could lead to writing to I/O port $4634 (or anything), which COULD crash the PC!

If my theory is right, then a solution could look like this:

-----8<----- SNIP

procedure SetPort(Address: Word; Value: Byte);
asm                // AX = Address, DL = Value
  push ax          // save Address
  mov  al,dl       // put Value into AL
  pop  dx          // get Address into DX
  out  dx,al
end;

----->8----- SNIP

This would swap the AX and DX registers (not exactly, because the value of DH would be lost, but that doesn't matter) and this way it uses the values from the registers as the parameter values.

But I don't know if this is always the case that the parameters' values are stored in the registers!!! HELP!

nova666.
0
 
LVL 3

Expert Comment

by:bryan7
Comment Utility
Have you tried:

procedure SetPort(Address: Word; Value: Byte); Assembler;
      asm                // AX = Address, DL = Value
        push ax          // save Address
        mov  al,dl       // put Value into AL
        pop  dx          // get Address into DX
        out  dx,al
      end;
0
 
LVL 4

Expert Comment

by:erajoj
Comment Utility
Hi nova666,
You're right. It usually works doing it your way.
But, you should always use the "assembler" directive (for compability reasons).

You're right on the AX, DL part. Actually, when two parameters are used as parameters, the 32 bit EAX register holds the value or pointer to the value depending on parameter type, and EDX hold the other. The result value from a function is located in the EAX register on exit. AX is the least significant 16 bit word in the EAX register and AL is the least significant byte in the AX register. The physical order in memory is reversed, on Intel processors, AL, AH, EAL, EAH, that's why the AL register is located first.
My suggestion to the function is, simply:

procedure SetPortByte(Value: Byte; Address: Word); assembler;
asm
  OUT DX, AL
end;

Example of function:

function AddPointers( pA, pB: Pointer ): Pointer; assembler;
asm
  ADD EAX, EDX // add pB to pA, which also is the result
end;

Don't hesitate to ask, these things are quite esoterical.

/// John

0
 
LVL 1

Expert Comment

by:jecksom
Comment Utility
Hi Nova66!


Did  you remind what you having IDT and port relocation/controling under win95(since you
wait to code with asm) .... how to get control under situation ? Write your own VXD !

Sorry , if i repeat somedoby .

Jecksom


PS: wanna example in asm ?

0
 
LVL 1

Expert Comment

by:jecksom
Comment Utility
hehee , i did read your comment dudes ! .....  how about LGDT op-code ? ;)
Jecksom
0
Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

 
LVL 4

Expert Comment

by:erajoj
Comment Utility
Sorry Jecksom,
I fail to find the amusing part about messing with the descriptor tables.
Could you please enlighten me?

BTW, LGDT is not an opcode, it's an instruction. [0F 01 /2] is it's opcode. :-)

/// John
0
 
LVL 1

Author Comment

by:nova666
Comment Utility
Hey, guys! Thanks for the loads of comments, but don't teach me assembler :)) I started with assembler on my good old C=64... Even there, the LSB came before the MSB in a Word (Words were rare since the 6510 was 8 bits, but for jumps, etc...). Maybe Intel stole the LSB/MSB thing? Who knows? <eg>

The 'assembler' keyword isn't needed anymore and 'only supported for compatibility' (Delphi help file).

I already knew about the x86 registers, the only problem was the 'interface' to Delphi. Since I didn't know how the parameters were passed over the function, it didn't seem logical for the second parameter to be passed in EDX. Why don't they put the 1st param in EAX, the 2nd in EBX (which is used and must be restored if changed in a proc/func, don't know why though), the 3rd in ECX and the 4th in EDX... THIS WOULD HAVE BEEN LOGICAL... :) It was clear to me, too, that the result is stored in EAX.

But, ok, they didn't, and now I do know it is ok to write my proc as suggested in my 1st comment. BTW: is this fact in the help files, or were is it documented???

Regarding the difference between BEGIN/ASM/END/END and ASM/END: some time ago I heard that ASM/END procs/funcs wouldn't be called, but used like a macro, i.e. compiled into the code where it is 'called' in the program. But this may apply to DOS Pascal only. Don't know. But this would have been a good reason to use ASM/END instead of BEGIN/ASM/END/END => speed issue! Well...

John (erajoj), it's good idea to reverse the parameters' order to spare the PUSH/MOV/POP's, but for some reason I like it as it was, i.e. 'Address' 1st, then 'Value' :-}

Jecksom, I don't exactly understand what you mean by IDT, port relocation/controlling!? I could write an extra driver, but this could be problematical since I'm using the I/O port read/write routines for a CPU temperature/fan monitoring tool that I'm writing, and the according chips on the motherboard (LM7x, Winbond) are already recognized by Win95 as 'Motherboard resources', and already have the I/O ports reserved, so an extra driver might not work. Besides it's WAY more practical for such a monitoring tool not requiring a driver to be installed before use :-)

I do know that this way the thing won't run under NT, but by utilising a VxD driver, it wouldn't run under NT either, so why the uneccessary work? Thanks for the suggestion, though!

Thank you again, guys, John in the first place for confirming my theory about the parameter passing.

John, if you want the points, post a pseudo-answer, just so I can give them to you... and maybe tell me where the thing is documented, if you know that.

nova666.
0
 
LVL 1

Author Comment

by:nova666
Comment Utility
Hmm, another thing!

What does LGDT do?

nova666,-)
0
 
LVL 4

Accepted Solution

by:
erajoj earned 150 total points
Comment Utility
Hi nova666,
Nothing in your question told me you spoke assembler, so I assumed you didn't.
That's why you got such a lame answer.
But, you're wrong on the endian stuff. The Motorola processors use big endian and Intel uses little endian.

LGDT loads data into the Global Descriptor Table (GDT). Here's what the docs say about LGDT/LIDT:

  Loads the values in the source operand into the global descriptor table register (GDTR) or the
  interrupt descriptor table register (IDTR). The source operand specifies a 6-byte memory loca-tion
  that contains the base address (a linear address) and the limit (size of table in bytes) of the
  global descriptor table (GDT) or the interrupt descriptor table (IDT). If operand-size attribute is
  32 bits, a 16-bit limit (lower 2 bytes of the 6-byte data operand) and a 32-bit base address (upper
  4 bytes of the data operand) are loaded into the register. If the operand-size attribute is 16
  bits, a 16-bit limit (lower 2 bytes) and a 24-bit base address (third, fourth, and fifth byte) are
  loaded. Here, the high-order byte of the operand is not used and the high-order byte of the base
  address in the GDTR or IDTR is filled with zeros.

  The LGDT and LIDT instructions are used only in operating-system software; they are not used
  in application programs. They are the only instructions that directly load a linear address (that
  is, not a segment-relative address) and a limit in protected mode. They are commonly executed
  in real-address mode to allow processor initialization prior to switching to protected mode.

For more info: http://www.x86.org/intel.doc/IntelDocs.html

Help file entries:
  Object Pascal Language Guide Help:
    Assembler procedures and functions
    Differences between Object Pascal and Assembler expressions
    Expression classes
    Function results
    Method calling conventions
    Operands
    Parameters << This is a good one
    Register saving conventions
    Register use
    Registers
    Symbols << This one is good too!
   
/// John

0
 
LVL 1

Author Comment

by:nova666
Comment Utility
Hi John,

I DO remember that on my C=64 (6510), the LSB *did* come before MSB..... Maybe they changed that on other Motorolas, but on the 6510, the LSB came first. Please kill me if I'm in error, but I do remember this :-)

Regarding the Delphi Help, I *have read* all the topics you mentioned (all topics about assembler), but I didn't find anything about parameter passing for assembler procs/funcs... Maybe I overlooked it, but don't think so!

Nevertheless thanks for your answers... :)

nova666.
0
 
LVL 4

Expert Comment

by:erajoj
Comment Utility
Hi again,
I will not give up on this...
It's all in the help file. Exactly where I told you.
Search the Object Pascal Language Guide helpfile for "EAX" and you will find it.
If you don't, please contact your optician for an examination. ;-)

And of course you're right, the 6500 series processors did use little endian. The 6800 series didn't. BTW, the Intel 8080 (1974) came out before the 6800 (1975). But the 6510 was built from guys who spun off from Motorola (in 1975) and formed MOS Technologies, so the 6510 isn't really Motorola. I used to hack on one of the first Commodore 64s myself, but that's history now.

/// John
0
 
LVL 1

Author Comment

by:nova666
Comment Utility
Hi John,

Yes, now I found it. I searched for EAX and chose the 'Parameters' topic, where the parameter passing is documented. (although this is only for 'register' procs/funcs, not specially for 'assembler' procs/funcs, but who cares? It will be the same for the two. <g>). Sorry for being blind :-)

nova666.
0

Featured Post

Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

Join & Write a Comment

Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
In this seventh video of the Xpdf series, we discuss and demonstrate the PDFfonts utility, which lists all the fonts used in a PDF file. It does this via a command line interface, making it suitable for use in programs, scripts, batch files — any pl…
When you create an app prototype with Adobe XD, you can insert system screens -- sharing or Control Center, for example -- with just a few clicks. This video shows you how. You can take the full course on Experts Exchange at http://bit.ly/XDcourse.

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now