2013-06-19 4 views
5

Ich schrieb eine printf myselef, die va_list/va_arg/va_start/va_end/va_arg verwenden.Verwenden Sie gcc kompilieren Sie ein Projekt, das "undefinierte Verweis auf` abort '"zeigt

typedef char *va_list; 
#define _AUPBND    (sizeof (acpi_native_int) - 1) 
#define _ADNBND    (sizeof (acpi_native_int) - 1) 
#define _bnd(X, bnd)   (((sizeof (X)) + (bnd)) & (~(bnd))) 
#define va_arg(ap, T)   (*(T *)(((ap) += (_bnd (T, _AUPBND))) - (_bnd (T,_ADNBND)))) 
#define va_end(ap)    (void) 0 
#define va_start(ap, A)   (void) ((ap) = (((char *) &(A)) + (_bnd (A,_AUPBND)))) 

Zunächst kopiere ich diese Makros von Linux-Kernel und die printf 32-Bit-Integer korrekt gedruckt werden kann, aber nicht 64-Bit-Integer drucken und Doppel/float drucken kann fehlschlagen oder collapse.Then prüfe ich den Code und Ich schätze, der va_ * könnte Fehler haben, also benutze ich __builtin_va_ * anstelle von kernel's va_ *.

typedef __builtin_va_list va_list; 
#define va_start(v,l) __builtin_va_start(v,l) 
#define va_end(v)  __builtin_va_end(v) 
#define va_arg(v,l)  __builtin_va_arg(v,l) 

Aber gcc prompt "undefined reference to` Abbruch '", so schreibe ich einen leeren Abbruch() und myprintf arbeitet corretly. Meine Fragen sind:

  1. Warum va_list/va_arg/va_start/va_end/va_arg der Linux-Kernel nicht für printf 64-Bit-Integer verwendet und Doppel/schweben?
  2. Als ich noch __builtin_va_start/__builtin_va_arg/__builtin_va_end/__builtin_va_list, warum gcc prompt „undefined reference to abort'"? But I can not find the definition of __builtin_va_ *`, Wo ist ihre Definition?
+2

Wie wäre es mit einem ?Auch '_bnd' (_bnd soll _va_align sein) ist dort anders definiert:' #define __va_align (ty) ((sizeof (ty) + sizeof (int) - 1) & ~ (sizeof (int) - 1)) ' –

+0

Stimmen Sie mit @Armin überein; Warum benutzt du nicht einfach den Standard-Header für va_arg Zeug? –

+0

@Oli Charlesworth in der Tat, unser Projekt arbeitet ohne os Unterstützung und wir brauchen Kontrolle, wo zu drucken, so dass die stdio.h ist nicht im Einklang mit unserer Anforderung. – Ezio

Antwort

0

Sie Ausschneiden und Einfügen Dinge nicht aus den Linux-Header. Stattdessen setzen diese auf dem Anfang der Quelldatei:

#include <stdarg.h> 

Dies wird Ihnen alles, was Sie brauchen, um va_list und va_arg zu verwenden, aber es wird nicht Zug in printf oder einem der Standard-I/O-stuf. f (das lebt in <stdio.h>).

1

gcc __builtin_va_arg() wird offenbar nennen abort() (zumindest auf einigen Plattformen oder Situationen), wenn sie mit einem Typ Argumente aufgerufen werden kann nicht im ... Teil der Argumentliste für einen Funktionsaufruf übergeben wurden.

zum Beispiel aufgrund von Förderungen ein char oder float als solches Argument übergeben wird int oder double gefördert wurden. Der Zugriff auf diese Argumente als va_arg(ap,char) oder va_arg(ap,float) ist undefiniertes Verhalten und GCC kann abort() in dieser Situation aufrufen - oder es kann etwas anderes tun (mein MinGW-Compiler wird eine ungültige Anweisung ausführen, um einen Absturz zu verursachen).

Man könnte so etwas wie dies sehen, wenn zusammengestellt:

In file included from D:\temp\test.c:2:0: 
D:\temp\test.c: In function 'foo': 
D:\temp\test.c:12:16: warning: 'char' is promoted to 'int' when passed through '...' [enabled by default] 
    c = va_arg(ap,char); 
       ^
D:\temp\test.c:12:16: note: (so you should pass 'int' not 'char' to 'va_arg') 
D:\temp\test.c:12:16: note: if this code is reached, the program will abort 

Die ‚Definition‘ von __builtin_va_* in den Compiler kompiliert (deshalb ‚builtin‘ ist Teil des Namens).

Was die Linux-Makros für varargs Zugang: während die Definitionen, die Sie von einem Linux-Kernel-Header nahm in existieren include/acpi/platform/acenv.h, wenn Sie in der Tat sorgfältig auf die bedingte Kompilierung suchen, Sie‘ Ich sehe, dass diese Makros beim Erstellen des Linux-Kernels nicht verwendet werden. Ich bin nicht genau sicher, wenn diese Makros in Kraft sind, aber sie werden nicht mit x64/x86-64/amd64-Builds arbeiten, da der ABI auf dieser Plattform nicht vollständig stack-basiert ist. Weitere Informationen finden Sie in Abschnitt 3.5.6 der "Binary-Schnittstelle für System V-Anwendungen - AMD64 Architecture Processor".

Verwandte Themen