From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 110870 invoked by alias); 22 Jun 2017 17:12:58 -0000 Mailing-List: contact libffi-discuss-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libffi-discuss-owner@sourceware.org Received: (qmail 110854 invoked by uid 89); 22 Jun 2017 17:12:57 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.3 required=5.0 tests=AWL,BAYES_00,RCVD_IN_DNSWL_LOW,SPF_PASS autolearn=ham version=3.3.2 spammy=anthony, HTo:U*green, Anthony, 22062017 X-HELO: smtp-out-so.shaw.ca Received: from smtp-out-so.shaw.ca (HELO smtp-out-so.shaw.ca) (64.59.136.139) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 22 Jun 2017 17:12:55 +0000 Received: from kylheku.com ([70.79.163.252]) by shaw.ca with SMTP id O5f1dbmOaeQWUO5f2dO0as; Thu, 22 Jun 2017 11:12:53 -0600 X-Authority-Analysis: v=2.2 cv=UpATD64B c=1 sm=1 tr=0 a=95A0EdhkF1LMGt25d7h1IQ==:117 a=95A0EdhkF1LMGt25d7h1IQ==:17 a=IkcTkHD0fZMA:10 a=SMorJkV_YP8A:10 a=LWSFodeU3zMA:10 a=SHwv7jZZv6IA:10 a=UJSGC2avfuZp5bpXmbQA:9 a=QEXdDO2ut3YA:10 Received: from www-data by kylheku.com with local (Exim 4.72) (envelope-from ) id 1dO5f0-0005B9-6X; Thu, 22 Jun 2017 10:12:50 -0700 To: Anthony Green Subject: Re: Does a =?UTF-8?Q?FFI=5FSTRUCT=20type=20really=20need=20the=20?= =?UTF-8?Q?elements=20array=3F?= X-PHP-Originating-Script: 501:rcmail.php MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: quoted-printable Date: Thu, 22 Jun 2017 17:12:00 -0000 From: Kaz Kylheku Cc: libffi-discuss@sourceware.org In-Reply-To: References: Message-ID: X-Sender: kaz@kylheku.com User-Agent: Roundcube Webmail/0.9.2 X-CMAE-Envelope: MS4wfHO6A3N/DoREJdRClfrjNbbEmMcxh9BiU7XYCZ9LrvgDiIdpd+fVECUit06/uzNW0sQJd/3VHz5zLgOdHaKcT6jyWX4AcTM1kCOAu71AcBcBDOhr1Y/W 0NrOvy4a2k9rdbh/OEJ3qxS7wo07a06qtD83+wDDqALZ5ii1PB+eEMkwkBQzBDcArxS1PXZOx2MbfY+EsInOCfNGVqyLRHumBuI= X-SW-Source: 2017/txt/msg00017.txt.bz2 On 22.06.2017 05:01, Anthony Green wrote: > Hi Kaz, >=20 > There are complexities around dealing with structs with nested struct=20 > elements. >=20 > It sounds like yours is a special case, where you are doing a lot of > work that is normally done by libffi, which is too bad. Hi Anthony, There is nothing too bad about it, the work of doing the struct member offset and alignment calculations are quite a small and easy subtask, relative to everything. Most of that "everything" is out of the scope of libffi. Those little calculations for offsets and whatnot aren't convenient if they have to be in a parallel framework of objects in a separate library. The main value in libffi is that it provides hand-coded machine language routines for doing call dispatch. Memory layouts can be done in portable C easily. Oh, and another requirement I have is that conversion between C objects and objects in my higher level language has to be supported even if libffi is not available (isn't detected by the configure=20 script). I have a "HAVE_LIBFFI" preprocessor symbol, such that everything still builds when it evaluates to zero. The foreign call/callback capability isn't there, but other features are, like reading a C struct from a=20 file, for instance. Why I wrote yesterday's posting is that I started adding support for unions, and realized that the elements[] array thing is getting in the way. I cannot fill that array with the union element types; libffi will miscalculate the size. Basically, the approach I'm going to take is to calculate the size based on the largest union element, then pad it according to the worst-case alignment, and stick those values into the ffi_type, which will be of FFI_TYPE_STRUCT. Then I might as well treat structs and arrays that way too. > The libffi API is far from perfect, but this is one area where there > have been few complaints. That being said, it would be interesting to > hear a more fully formed proposal that could be considered prior to a > major API breaking release. For the people that rely on the struct member calculations, it would probably be helpful to have these requirements: * A way to request the calculation to be done after preparing the tree of types: like a void ffi_type_init(ffi_type *) function or whatever. You shouldn't have to involve a ffi_type in the construction of a call descriptor in order to get libffi to calculate its size, alignment and member offsets. * the elements[] array should be an array of structures which provide the offset information. (I have exactly such an array in my own struct: it holds offsets, and also shift values and masks for bitfields.) For backward compatibility, elements can be kept as-is (array of ffi_type * pointers), but a parallel array can be added for the extra info. If that array pointer is not null, it gets filled in. * unions could be supported with a FFI_TYPE_UNION which simply puts all the elements at offset zero and does the size and alignment calculation accordingly. I get your comment about API breaking. If members are added to ffi_type, and something like ELF versioning is not used, then clients compiled with the old headers cannot work with a new lib. Any types like ffi_type that are allocated by client code should contain padding members for future extension. I see in ffi.h that we have this: typedef struct _ffi_type { size_t size; unsigned short alignment; unsigned short type; struct _ffi_type **elements; } ffi_type; which is somewhat of a mistake; there should be something at the end=20 like void *pad[4]; /* reserved for future extension */ possibly along with the requirement that all correctly written client code must do memset(&type->pad, 0, sizeof type->pad) or equivalent, such as using calloc for these objects or whatever. That requirement makes it possible, in the future, to add members to the structure whose initialization responsibility rests with the application. not just members that are managed internally by the library. Other possibilities are to have a version handshake; have a pair of preprocessor symbols FFI_MAJOR and FFI_MINOR which are passed to some call like ffi_init(FFI_MAJOR, FFI_MINOR). Then libffi knows exactly which version of the header file the binary client was compiled with. It knows that an old client wouldn't have initialized members that do not exist in its version of the struct declaration. If the space is reserved, it can be treated as uninitialized, and used. If the space is not reserved, the library can avoids touching it. Cheers ...