use*_*064 8 c gcc x86-64 variadic-functions
我的问题vsprintf是我无法直接获取输入参数,我必须首先获取输入并将它们保存在void**,然后传递void**给vsprintf()它,这对于windows来说都很好,但是当我来到64位linux时,gcc无法编译因为它不允许转换void**为va_list,是否有人可以给我一些帮助我应该如何在linux下执行此操作?
我可以在GCC中动态创建va_list吗?
void getInputArgs(char* str, char* format, ...)
{
va_list args;
va_start(args, format);
vsprintf(str, format, args);
va_end(args);
}
void process(void)
{
char s[256];
double tempValue;
char * tempString = NULL;
void ** args_ptr = NULL;
ArgFormatType format; //defined in the lib I used in the code
int numOfArgs = GetNumInputArgs(); // library func used in my code
if(numOfArgs>1)
{
args_ptr = (void**) malloc(sizeof(char)*(numOfArgs-1));
for(i=2; i<numOfArgs; i++)
{
format = GetArgType(); //library funcs
switch(format)
{
case ArgType_double:
CopyInDoubleArg(i, TRUE, &tempValue); //lib func
args_ptr[i-2] = (void*) (int)tempValue;
break;
case ArgType_char:
args_ptr[i-2]=NULL;
AllocInCharArg(i, TRUE, &tempString); //lib func
args_ptr[i-2]= tempString;
break;
}
}
}
getInputArgs(s, formatString, (va_list) args_ptr); //Here
// is the location where gcc cannot compile,
// Can I and how if I can create a va_list myself?
}
Run Code Online (Sandbox Code Playgroud)
有一种方法可以做到这一点,但它是具体到gccLinux上.它适用于32位和64位版本的Linux(已测试).
免责声明:我不赞同使用此代码.它不是便携式的,它是黑客的,而且坦率地说是一个岌岌可危的平衡大象.我只是在证明可以动态创建一个va_list使用gcc,这是原始问题所要求的.
话虽如此,下面的文章详细介绍了如何va_list使用amd64 ABI:Amd64和Va_arg.
通过对结构va_list体内部结构的了解,我们可以将va_arg宏从一个va_list我们自己构建的内容中汲取阅读:
#if (defined( __linux__) && defined(__x86_64__))
// AMD64 byte-aligns elements to 8 bytes
#define VLIST_CHUNK_SIZE 8
#else
#define VLIST_CHUNK_SIZE 4
#define _va_list_ptr _va_list
#endif
typedef struct {
va_list _va_list;
#if (defined( __linux__) && defined(__x86_64__))
void* _va_list_ptr;
#endif
} my_va_list;
void my_va_start(my_va_list* args, void* arg_list)
{
#if (defined(__linux__) && defined(__x86_64__))
/* va_args will read from the overflow area if the gp_offset
is greater than or equal to 48 (6 gp registers * 8 bytes/register)
and the fp_offset is greater than or equal to 304 (gp_offset +
16 fp registers * 16 bytes/register) */
args->_va_list[0].gp_offset = 48;
args->_va_list[0].fp_offset = 304;
args->_va_list[0].reg_save_area = NULL;
args->_va_list[0].overflow_arg_area = arg_list;
#endif
args->_va_list_ptr = arg_list;
}
void my_va_end(my_va_list* args)
{
free(args->_va_list_ptr);
}
typedef struct {
ArgFormatType type; // OP defined this enum for format
union {
int i;
// OTHER TYPES HERE
void* p;
} data;
} va_data;
Run Code Online (Sandbox Code Playgroud)
现在,我们可以va_list使用类似您的process()方法或以下内容生成指针(对于64位和32位构建都是相同的):
void* create_arg_pointer(va_data* arguments, unsigned int num_args) {
int i, arg_list_size = 0;
void* arg_list = NULL;
for (i=0; i < num_args; ++i)
{
unsigned int native_data_size, padded_size;
void *native_data, *vdata;
switch(arguments[i].type)
{
case ArgType_int:
native_data = &(arguments[i].data.i);
native_data_size = sizeof(arguments[i]->data.i);
break;
// OTHER TYPES HERE
case ArgType_string:
native_data = &(arguments[i].data.p);
native_data_size = sizeof(arguments[i]->data.p);
break;
default:
// error handling
continue;
}
// if needed, pad the size we will use for the argument in the va_list
for (padded_size = native_data_size; 0 != padded_size % VLIST_CHUNK_SIZE; padded_size++);
// reallocate more memory for the additional argument
arg_list = (char*)realloc(arg_list, arg_list_size + padded_size);
// save a pointer to the beginning of the free space for this argument
vdata = &(((char *)(arg_list))[arg_list_size]);
// increment the amount of allocated space (to provide the correct offset and size for next time)
arg_list_size += padded_size;
// set full padded length to 0 and copy the actual data into the location
memset(vdata, 0, padded_size);
memcpy(vdata, native_data, native_data_size);
}
return arg_list;
}
Run Code Online (Sandbox Code Playgroud)
最后,我们可以使用它:
va_data data_args[2];
data_args[0].type = ArgType_int;
data_args[0].data.i = 42;
data_args[1].type = ArgType_string;
data_args[1].data.p = "hello world";
my_va_list args;
my_va_start(&args, create_arg_pointer(data_args, 2));
vprintf("format string %d %s", args._va_list);
my_va_end(&args);
Run Code Online (Sandbox Code Playgroud)
你有它.它的工作方式与普通和宏大致相同,但允许您传递自己动态生成的字节对齐指针,而不是依赖于调用约定来设置堆栈帧.va_startva_end
我尝试过使用其他地方提到的 libffi 并且它有效。下面是链接,希望对遇到类似问题的人有所帮助。再次感谢我在这里得到的所有帮助!
链接: http: //www.atmark-techno.com/~yashi/libffi.html -- 给出的简单示例 http://www.swig.org/Doc1.3/Varargs.html -- printf() 和其他示例给定