|
|||
|
I'm converting some code written for Gnat to compile with Apex. The
software has bindings to C functions (OS calls). Some of these take System.Address as parameters. Apex complains about the variables used in these calls (via 'Address) because they not volatile or aliased (or imported, exported, etc.). My question is: which should I use? Is there any difference whether a variable is volatile or aliased? I am assuming the compiler is concerned about the variable possibly being changed in the call (which, of course, is true). Is there a way to satisfy the compiler without stopping optimizations of the variable after the call, or do I need to use a second variable to do this? |
|
|
||||
|
||||
|
|
|
|||
|
"REH" <spamjunk@stny.rr.com> writes:
> I'm converting some code written for Gnat to compile with Apex. The > software has bindings to C functions (OS calls). Some of these take > System.Address as parameters. Apex complains about the variables used > in these calls (via 'Address) because they not volatile or aliased (or > imported, exported, etc.). My question is: which should I use? Is > there any difference whether a variable is volatile or aliased? > > I am assuming the compiler is concerned about the variable possibly > being changed in the call (which, of course, is true). Is there a way > to satisfy the compiler without stopping optimizations of the variable > after the call, or do I need to use a second variable to do this? I like this warning given by Apex; I think it would be nice if GNAT would also warn in this situation. pragma Volatile (Variable) says the compiler must not optimise away any reads or writes to that variable, and that it may not add extra reads or writes beyond those you explicitly request in your program text. You want to use that for hardware registers, where a "read" operation may have a side effect such as changing the device's state. Whenever you access a variable through an address value, the variable is aliased, so you should say that explicitly. Otherwise, the compiler may be tempted to place the variable in a processor register, which has no address. In addition, pragma Import (Ada, Variable) says that the compiler may not insert default initialisations for that variable, or assume anything about the value of the variable, before you write to it. But the compiler may do optimisations, because it is allowed to assume that no side effects occur when you read from or write to the variable (that is, side effects not explicitly requested from the program text). In your situation, it seems that you want something like this (which, incidentally, I use very often): type T is ...; procedure Read_Variable (At_Address : in System.Address; Into : out T) is V : aliased T; -- suppress default initialisation, I know what I'm doing. pragma Import (Ada, V); for V'Address use At_Address; begin -- perform my own explicit validation of the variable, perhaps -- using 'Valid; then, copy into Into: Into := V; end Read_Variable; -- Ludovic Brenta. |
|
|||
|
Ludovic Brenta wrote: > I like this warning given by Apex; I think it would be nice if GNAT > would also warn in this situation. > > pragma Volatile (Variable) says the compiler must not optimise away > any reads or writes to that variable, and that it may not add extra > reads or writes beyond those you explicitly request in your program > text. You want to use that for hardware registers, where a "read" > operation may have a side effect such as changing the device's state. > > Whenever you access a variable through an address value, the variable > is aliased, so you should say that explicitly. Otherwise, the > compiler may be tempted to place the variable in a processor register, > which has no address. > > In addition, pragma Import (Ada, Variable) says that the compiler may > not insert default initialisations for that variable, or assume > anything about the value of the variable, before you write to it. But > the compiler may do optimisations, because it is allowed to assume > that no side effects occur when you read from or write to the variable > (that is, side effects not explicitly requested from the program > text). In your situation, it seems that you want something like this > (which, incidentally, I use very often): > > type T is ...; > > procedure Read_Variable (At_Address : in System.Address; > Into : out T) is > V : aliased T; > -- suppress default initialisation, I know what I'm doing. > pragma Import (Ada, V); > for V'Address use At_Address; > begin > -- perform my own explicit validation of the variable, perhaps > -- using 'Valid; then, copy into Into: > Into := V; > end Read_Variable; > > -- > Ludovic Brenta. VERY helpful! Thank you so much. I'm dealing with a situation where I have to do symbol table lookups from the OS which return an address to procedure or function. This is done in several places in the code. The reason is I have to support different hardware dynamically. For example, if I am on board A, I call Foo. The comparible subprogram on B is Bar. So, I cannot just make pragma exports for them both as one will be undefined. Anyways, to make it easier, I wanted to make a generic which just returned an access type without having to do the pragma Import and for X'address in every case. Then calling the subprogram is simple. My first pass is: generic type Data_Type is private; type Data_Ptr is access all Data_Type; function Address_To_Access(Addr : System.Address) return Data_Ptr; function Address_To_Access(Addr : System.Address) return Data_Ptr is begin if Addr = System.Null_Address then return null; else declare Data: aliased Data_Type; for Data'Address use Addr; begin return Data'Unchecked_Access; end; end if; end Address_To_Access; Two questions: 1) Is this even a smart thing to do? 2) How would I define a generic like the above for an subprogram with an unknown signature? Thanks again for the help. REH |
|
|||
|
"REH" <spamjunk@stny.rr.com> writes:
> VERY helpful! Thank you so much. > > I'm dealing with a situation where I have to do symbol table lookups > from the OS which return an address to procedure or function. This is > done in several places in the code. The reason is I have to support > different hardware dynamically. For example, if I am on board A, I > call Foo. The comparible subprogram on B is Bar. So, I cannot just > make pragma exports for them both as one will be undefined. Anyways, > to make it easier, I wanted to make a generic which just returned an > access type without having to do the pragma Import and for X'address in > every case. Then calling the subprogram is simple. My first pass is: > > generic > type Data_Type is private; > type Data_Ptr is access all Data_Type; > function Address_To_Access(Addr : System.Address) return Data_Ptr; > > function Address_To_Access(Addr : System.Address) return Data_Ptr is > begin > if Addr = System.Null_Address then > return null; > else > declare > Data: aliased Data_Type; > for Data'Address use Addr; > begin > return Data'Unchecked_Access; > end; > end if; > end Address_To_Access; > > > Two questions: > 1) Is this even a smart thing to do? Why do you have to use a generic? Why not just: procedure Call_Procedure (At_Address : in System.Address) is procedure Proc; for Proc'Address use At_Address; begin Proc; end Call_Procedure; The above effectively converts from an address to an access-to-procedure, and calls the procedure. If what you want is convert from an address to an access-to-data, you should probably use Ada.Address_To_Access_Conversions. > 2) How would I define a generic like the above for an subprogram with > an unknown signature? I don't know how you could call a procedure with unknown parameters. Or perhaps you mean with one known parameter which is the address of a record containing arbitrary parameters? generic type Parameter_Type is limited private; -- [1] procedure Call_Procedure (At_Address : in System.Address; Params : in Parameter_Type); procedure Call_Procedure (At_Address : in System.Address; Params : in Parameter_Type) is procedure Proc (Params : in System.Address); for Proc'Address use At_Address; begin Proc (Params'Address); end Call_Procedure; Is this close to what you want? [1] I think the type has to be declared limited, so that it is always passed by reference to Call_Procedure. This guarantees that the parameter has an address, and is not in a register. I have not compiled or tried this code, so please take it with due care. -- Ludovic Brenta. |
|
|||
|
Ludovic Brenta wrote: > Why do you have to use a generic? Why not just: > > procedure Call_Procedure (At_Address : in System.Address) is > procedure Proc; > for Proc'Address use At_Address; > begin > Proc; > end Call_Procedure; I was just trying to by lazy, and not do that everytime. If I have to, I have to. > > I don't know how you could call a procedure with unknown parameters. > Or perhaps you mean with one known parameter which is the address of > a record containing arbitrary parameters? The caller would know. What I don't know to do (and probably can't) is define a generic that can be instantiated using *any* access type, even one to a subprogram. I guess I am spending more time trying to avoid work, than just doing it. REH |
|
|||
|
"REH" <spamjunk@stny.rr.com> writes:
> Ludovic Brenta wrote: >> Why do you have to use a generic? Why not just: >> >> procedure Call_Procedure (At_Address : in System.Address) is >> procedure Proc; >> for Proc'Address use At_Address; >> begin >> Proc; >> end Call_Procedure; > > I was just trying to by lazy, and not do that everytime. If I have to, > I have to. I don't understand. Do you mean to say that one Call_Procedure is not sufficient? That you'd have to have many such procedures? Why? >> I don't know how you could call a procedure with unknown parameters. >> Or perhaps you mean with one known parameter which is the address of >> a record containing arbitrary parameters? > The caller would know. What I don't know to do (and probably can't) is > define a generic that can be instantiated using *any* access type, even > one to a subprogram. > > I guess I am spending more time trying to avoid work, than just doing > it. In my example, the Parameter_Type can contain an access-to-subprogram. Of course, you need to instantiate the generic once per parameter profile, and there may be many different ones, so that the generic doesn't really save you much work. -- Ludovic Brenta. |
|
|||
|
Ludovic Brenta wrote: > I don't understand. Do you mean to say that one Call_Procedure is not > sufficient? That you'd have to have many such procedures? Why? I've not sure if you are asking if I need several procedures per address (I do not) or why I have many address (I do). Either way, your way is probably best: just make one wrapper procedure for each address. I was "creating" the procedure from the address at each call point. Sigh. Sometimes the simplest answer eludes me. Thanks for the great advice. REH |
|
|||
|
Ludovic Brenta <ludovic@ludovic-brenta.org> writes:
> procedure Call_Procedure (At_Address : in System.Address) is > procedure Proc; > for Proc'Address use At_Address; > begin > Proc; > end Call_Procedure; With GCC 4.0.0, you need to say pragma Import (C, Proc); as well. with Ada.Text_IO; use Ada.Text_IO;With System; procedure Acc is procedure Call (At_Address : System.Address) is procedure Proc; pragma Import (C, Proc); for Proc'Address use At_Address; begin Proc; end Call; procedure Callee is begin Put_Line ("hello world."); end Callee; begin Call (Callee'Address); end Acc; |
|
|||
|
"Ludovic Brenta" <ludovic@ludovic-brenta.org> wrote in message
news:87mzlnomca.fsf@ludovic-brenta.org... .... > In your situation, it seems that you want something like this > (which, incidentally, I use very often): > > type T is ...; > > procedure Read_Variable (At_Address : in System.Address; > Into : out T) is > V : aliased T; > -- suppress default initialisation, I know what I'm doing. > pragma Import (Ada, V); > for V'Address use At_Address; > begin > -- perform my own explicit validation of the variable, perhaps > -- using 'Valid; then, copy into Into: > Into := V; > end Read_Variable; This seems like a good time to mention that I think the explicit use of System.Address in Ada 95 and Ada 200Y code is usually a mistake. Since pragma Convention can be used to ensure that general access types have the appropriate representation, its rare that Address needs to be used for interfacing. (There is only a handful of uses of Address in Claw, for example.) Moreover, when you *do* need to use it, Address_to_Access_Conversions is the best way to convert it, not an overlay (which at best blocks optimizations and at worst won't even work right). type T is ...; procedure Read_Variable (At_Address : in System.Address; Into : out T) is package AAC is new System.Address_to_Access_Conversions (T); V : AAC.Object_Pointer := AAC.To_Pointer (At_Address); begin -- perform my own explicit validation of the pointer's contents, perhaps -- using 'Valid; then, copy into Into: Into := V.all; end Read_Variable; But it is better still to declare an appropriate type and never use Address in the first place: type Pointer_T is access all T; pragma Convention (C, Pointer_T); Address clauses should be restricted to mapping to hardware, IMHO. Randy. |
|
|||
|
"REH" <spamjunk@stny.rr.com> writes:
> Ludovic Brenta wrote: >> I don't understand. Do you mean to say that one Call_Procedure is not >> sufficient? That you'd have to have many such procedures? Why? > I've not sure if you are asking if I need several procedures per > address (I do not) or why I have many address (I do). Either way, your > way is probably best: just make one wrapper procedure for each > address. I was "creating" the procedure from the address at each call > point. Sigh. Sometimes the simplest answer eludes me. Even simpler: you need just one wrapper per parameter profile, i.e. one wrapper for all parameterless procedures, etc. -- Ludovic Brenta. |
|
|||
|
Ludovic Brenta wrote:
> pragma Volatile (Variable) says the compiler must not optimise away > any reads or writes to that variable, and that it may not add extra > reads or writes beyond those you explicitly request in your program > text. You want to use that for hardware registers, where a "read" > operation may have a side effect such as changing the device's state. Interesting! So with pragma Volatile (X) the following two statements are not the same: Y := X * X; Y := X ** 2; Good to know! Martin -- mailto://krischik@users.sourceforge.net Ada programming at: http://ada.krischik.com |
|
|||
|
On Thu, 06 Oct 2005 10:05:38 +0200, Martin Krischik wrote:
> Ludovic Brenta wrote: > >> pragma Volatile (Variable) says the compiler must not optimise away >> any reads or writes to that variable, and that it may not add extra >> reads or writes beyond those you explicitly request in your program >> text. You want to use that for hardware registers, where a "read" >> operation may have a side effect such as changing the device's state. > > Interesting! So with pragma Volatile (X) the following two statements are > not the same: > > Y := X * X; > Y := X ** 2; > > Good to know! BTW, even without Volatile, they are not necessary same! For intervals X*X /= X**2! Example: [-1, 2] * [-1, 2] = [-1, 4] [-1, 2]**2 = [2, 4] X**2 is as twice as more accurate than X*X. To improve accuracy of * and /, arguments need to be analyzed for dependency. X + X = 2 * X, no matter what. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de |
|
|||
|
Martin Krischik wrote:
> Ludovic Brenta wrote: > > > pragma Volatile (Variable) says the compiler must not optimise away > > any reads or writes to that variable, and that it may not add extra > > reads or writes beyond those you explicitly request in your program > > text. You want to use that for hardware registers, where a "read" > > operation may have a side effect such as changing the device's state. > > Interesting! So with pragma Volatile (X) the following two statements are > not the same: > > Y := X * X; > Y := X ** 2; Do we have a difference to C/C++ increment operator here? consider pragma Volatile (x); x := x + 1; -- (1) vs. x++; -- (2) In the Ada case (1) we are forced to have "read from memory", "increment" and "write to memory" instructions, whereas in C/C++ (2) you can get a single "increment memory" instruction (presuming the mentioned assembler instructions exist on a given processor) Rolf |
|
|||
|
Randy Brukardt wrote: > This seems like a good time to mention that I think the explicit use of > System.Address in Ada 95 and Ada 200Y code is usually a mistake. Since > pragma Convention can be used to ensure that general access types have the > appropriate representation, its rare that Address needs to be used for > interfacing. (There is only a handful of uses of Address in Claw, for > example.) > > Moreover, when you *do* need to use it, Address_to_Access_Conversions is the > best way to convert it, not an overlay (which at best blocks optimizations > and at worst won't even work right). > > type T is ...; > > procedure Read_Variable (At_Address : in System.Address; > Into : out T) is > package AAC is new System.Address_to_Access_Conversions (T); > V : AAC.Object_Pointer := AAC.To_Pointer (At_Address); > begin > -- perform my own explicit validation of the pointer's contents, perhaps > -- using 'Valid; then, copy into Into: > Into := V.all; > end Read_Variable; > > But it is better still to declare an appropriate type and never use Address > in the first place: > > type Pointer_T is access all T; > pragma Convention (C, Pointer_T); > > Address clauses should be restricted to mapping to hardware, IMHO. > > Randy. Randy, That's good stuff. Will it still apply when the address is to a subprogram? Can Address_to_Access_Conversions be instantiated with a subprogram? That's what I've been trying to do, but I don't know how to make a generic that takes an access to an arbitrary subprogram type. So, I think I am "stuck" using the for X'address specification. Thanks, REH |
|
|
![]() |
| Thread Tools | |
| Display Modes | |
|
|