2013-06-19 3 views
5

Я написал printf myselef, который использует va_list/va_arg/va_start/va_end/va_arg.использовать gcc компилировать проект, который показывает «неопределенная ссылка на` abort »

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)))) 

Сначала я копирую эти макросы из Linux ядра и Printf может напечатать 32-разрядное целое число правильно, но не может печатать 64-разрядное целое число и напечатать двойной/поплавок может обанкротиться или collapse.Then проверить код и Я думаю, у va_ * могут быть ошибки, поэтому я использую __builtin_va_ * вместо 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) 

Но НКА подсказки "неопределенная ссылка на` прерывания '", так что я пишу пустой Abort() и myprintf работу corretly. Мои вопросы:

  1. Почему Linux ядро ​​так va_list/va_arg/va_start/va_end/va_arg не может использоваться для printf 64-разрядных целого числа и двойного/плавать?
  2. Когда я __builtin_va_start/__builtin_va_arg/__builtin_va_end/__builtin_va_list, почему НКУ подсказка «неопределенная ссылка на abort'"? But I can not find the definition of __builtin_va_ *`, их определение Куда?
+2

Как насчет ?Также '_bnd' (_bnd предполагается ot быть _va_align) определяется по-разному:' #define __va_align (ty) ((sizeof (ty) + sizeof (int) - 1) & ~ (sizeof (int) - 1)) ' –

+0

Согласен с @Armin; почему вы не просто используете стандартный заголовок для va_arg? –

+0

@ Oli Charlesworth действительно, наш проект работает без поддержки os, и мы не контролируем, где печатать, поэтому stdio.h не соответствует нашему требованию. – Ezio

ответ

0

Не вырезать и вставлять вещи из заголовков Linux. Вместо этого поместите это на верхняя часть исходного файла:

#include <stdarg.h> 

Это даст вам все, что нужно для того, чтобы использовать va_list и va_arg Однако не будет тянуть в printf или любой стандартный I/O Stuf. f (живет в <stdio.h>).

1

ССЗ __builtin_va_arg() по-видимому, будет вызывать abort() (по крайней мере, на некоторых платформах или ситуации), если она вызвана с аргументом типа не может быть принят в ... части списка аргументов для вызова функции.

Например, из-за акции char или float передается в качестве такого аргумента будет был повышен до int или double. Доступ к этим аргументам как va_arg(ap,char) или va_arg(ap,float) - это неопределенное поведение, и gcc может вызвать abort() в этой ситуации - или он может сделать что-то еще (мой компилятор MinGW выполнит недопустимую команду, чтобы вызвать сбой).

Вы можете увидеть что-то вроде этого при компиляции:

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 

«определение» из __builtin_va_* компилируется в компиляторе (именно поэтому «встроенные» является частью названия).

Что касается макросов Linux для доступа к varargs: в то время как определения, взятые из заголовка ядра Linux, существуют в include/acpi/platform/acenv.h, если вы внимательно посмотрите на условную компиляцию, Посмотрим, что эти макросы не используются при построении ядра linux. Я не совсем уверен, когда эти макросы действуют, но они не будут работать с сборками x64/x86-64/amd64, потому что ABI на этой платформе не полностью основан на стеках. Подробности см. В разделе 3.5.6 «Бинарный интерфейс приложения System V Application - Приложение архитектуры AMD64».

Смежные вопросы