Patrick wrote:
> [...] I get an
> error when doing a SEC_ASN1EncodeItem(0, result, &sdrResult, template); the
> error has something to do with the template used
> (SECOID_AlgorithmIDTemplate)...Can't figure it out (had no problem on Unix
> with this).

Patrick,

You have run into a fundamental difference between Windows DLLs and 
Unix DSOs.  

> I had to use NSS_Get_SECOID_AlgorithmIDTemplate instead of
> SECOID_AlgorithmIDTemplate in order to get the code to compile:
> 
> static SEC_ASN1Template template[] = {
> { SEC_ASN1_SEQUENCE, 0, NULL, sizeof (SDRResult) },
> { SEC_ASN1_OCTET_STRING, offsetof(SDRResult, keyid) },
> { SEC_ASN1_INLINE, offsetof(SDRResult, alg),
> NSS_Get_SECOID_AlgorithmIDTemplate },
> { SEC_ASN1_OCTET_STRING, offsetof(SDRResult, data) },
> { 0 }
> };

You have a static initialized data structure.  Its contents are 
initialized by the linker/loader when the process begins to run, not 
by code that's compiled into the executable.  One of those pieces of 
initialized data is a pointer, initialized with the address of another 
piece of data (a template) from another shared library.  

A Unix loader typically has no trouble doing that (initializing a global 
pointer with the address of a piece of data from another DSO).  The 
Unix loader "fixes up" the address in the initialized pointer during the 
load process, so that the address in the initialized pointer is no longer
identical to the value in the DSO file, but is the corrected address in 
the process's virtual address space of that other data item.

But the loader in Windows cannot do that.  The windows loader cannot 
change addresses of data in memory at load time.  So, in practice, in
Windows, you cannot initialize a static/global pointer with the address
of a data item in another DLL.  You also cannot assign the address of a
data item from another DLL to a pointer in Windows.  However, you _can_
initialize or assign a static/global pointer with the address of a 
_function_ in another DLL.

There are two ways to solve the problem you've encountered.  

1. Have an exact copy of the template in your own code.  Don't reference 
a template from another a DLL, but rather reference your own copy of that
template. Templates are all constant, so this is not terribly unreasonable.
This is by far the simpler of the two solutions.

2. Use the special macros that I wrote in secasn1t.h to work around this 
problem.  Those macros are SEC_ASN1_MKSUB, SEC_ASN1_XTRN and SEC_ASN1_SUB. 
Change the reference for the AlgorithmIDTemplate from this:

    { SEC_ASN1_INLINE, offsetof(SDRResult, alg), SECOID_AlgorithmIDTemplate },

to this:

    { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(SDRResult, alg), 
      SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },

Then, in your source file, before the place where that template is declared,
add this line of code (outside of any function)

SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)   /* note: no trailing semicolon */

You can look at nss/lib/pkcs7/p7local.c for examples of the use of these
macros.

The use of these macros will generate the right code for each platform.

> When my app runs, Windows throws an "Exception Breakpoint error: breakpoint
> has been reached (0x800000003)" error message...I attached the stack trace
> from MSVC++.

> Is there a bug here? What's the Breakpoint error all about?

You changed the third part of the triplet to be correct for Windows, but
you didn't change the first part to go with it.

> Also, what's the difference between   NSS_Get_SECOID_AlgorithmIDTemplate
> and  SEC_ASN1_GET(SECOID_AlgorithmIDTemplate  )?

The SEC_ASN1_GET macro is another of these special macros that deals 
with getting the address of a template from another DLL.  Unlike 
SEC_ASN1_XTRN and SEC_ASN1_SUB, which are used to initialize static/global
pointers, SEC_ASN1_GET is used when the address of the template is going
to be referenced in an assignment of some kind.  Instead of coding:

const SEC_ASN1Template *theTemplate = SECOID_AlgorithmIDTemplate;

you would code:

const SEC_ASN1Template *theTemplate = SEC_ASN1_GET(SECOID_AlgorithmIDTemplate);

That generates the correct code on all platforms.  Look for examples
of its use in nss/lib/pkcs7/p7local.c 

On windows, SEC_ASN1_GET(SECOID_AlgorithmIDTemplate) expands to a function
call like this:  
        NSS_Get_SECOID_AlgorithmIDTemplate(NULL, PR_FALSE)
That function returns the address of the template from the other DLL.

On unix, SEC_ASN1_GET(SECOID_AlgorithmIDTemplate) expands to just 
        SECOID_AlgorithmIDTemplate 
since Unix doesn't have any trouble with addresses in other DSOs.

> -- Patrick

--
Nelson Bolyard               Netscape 
Disclaimer:                  I speak for myself, not for Netscape

Reply via email to