If you compile the following with "clang -S -emit-llvm struct.c"
struct _mystruct {
long long int a;
long long int b;
};
struct _mystruct foo(struct _mystruct s) {
s.a += 1;
return s;
}
int main(void) {
struct _mystruct s;
s.a = 8;
s.b = 9;
s = foo(s);
return s.a;
}
... you get (among other things):
define { i64, i64 } #foo(i64 %s.coerce0, i64 %s.coerce1) #0 {
Why does clang split the argument to foo in two? Is there any way I can prevent it from doing that? I want to be able to call it from other LLVM generated code that expects only one argument to foo.
Since LLVM has no way to represent it, Clang encodes the platform ABI this way. In this particular example, it's struct passing by-value which is extremely ABI specific. You will notice this if you provide different target triple to clang - you'll notice that the emitted code is different. I assume from the question this is run on a x64 machine where structs can be passed in registers.
Related
The codes:
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
typedef unsigned int uint32_t;
float average(int n_values, ... )
{
va_list var_arg;
int count;
float sum = 0;
va_start(var_arg, n_values);
for (count = 0; count < n_values; count += 1) {
sum += va_arg(var_arg, signed long long int);
}
va_end(var_arg);
return sum / n_values;
}
int main(int argc, char *argv[])
{
(void)argc;
(void)argv;
printf("hello world!\n");
uint32_t t1 = 1;
uint32_t t2 = 4;
uint32_t t3 = 4;
printf("result:%f\n", average(3, t1, t2, t3));
return 0;
}
When I run in ubuntu (x86_64), It's Ok.
lix#lix-VirtualBox:~/test/c$ ./a.out
hello world!
result:3.000000
lix#lix-VirtualBox:~/test/c$ uname -a
Linux lix-VirtualBox 4.4.0-116-generic #140-Ubuntu SMP Mon Feb 12 21:23:04 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
lix#lix-VirtualBox:~/test/c$
But when I cross-compiler and run it in openwrt(ARM 32bit), It's wrong.
[root#OneCloud_0723:/root/lx]#./helloworld
hello world!
result:13952062464.000000
[root#OneCloud_0723:/root/lx]#uname -a
Linux OneCloud_0723 3.10.33 #1 SMP PREEMPT Thu Nov 2 19:55:17 CST 2017 armv7l GNU/Linux
I know do not call va_arg with an argument of the incorrect type. But Why we can get right result in x86_64 not in arm?
Thank you.
On x86-64 Linux, each 32-bit arg is passed in a separate 64-bit register (because that's what the x86-64 System V calling convention requires).
The caller happens to have zero-extended the 32-bit arg into the 64-bit register. (This isn't required; the undefined behaviour in your program could bite you with a different caller that left high garbage in the arg-passing registers.)
The callee (average()) is looking for three 64-bit args, and looks in the same registers where the caller put them, so it happens to work.
On 32-bit ARM, long long is doesn't fit in a single register, so the callee looking for long long args is definitely looking in different places than where the caller placed uint32_t args.
The first 64-bit arg the callee sees is probably ((long long)t1<<32) | t2, or the other way around. But since the callee is looking for 6x 32 bits of args, it will be looking at registers / memory that the caller didn't intend as args at all.
(Note that this could cause corruption of the caller's locals on the stack, because the callee is allowed to clobber stack args.)
For the full details, look at the asm output of your code with your compiler + compile options to see what exactly what behaviour resulted from the C Undefined Behaviour in your source. objdump -d ./helloworld should do the trick, or look at compiler output directly: How to remove "noise" from GCC/clang assembly output?.
On my system (x86_64)
#include <stdio.h>
int main(void)
{
printf("%zu\n", sizeof(long long int));
return 0;
}
this prints 8, which tells me that long long int is 64bits wide, I don't know
the size of a long long int on arm.
Regardless your va_arg call is wrong, you have to use the correct type, in
this case uint32, so your function has undefined behaviour and happens to get
the correct values. average should look like this:
float average(int n_values, ... )
{
va_list var_arg;
int count;
float sum = 0;
va_start(var_arg, n_values);
for (count = 0; count < n_values; count += 1) {
sum += va_arg(var_arg, uint32_t);
}
va_end(var_arg);
return sum / n_values;
}
Also don't declare your uint32_t as
typedef unsigned int uint32_t;
this is not portable, because int is not guaranteed to be 4 bytes long across
all architectures. The Standard C Library actually declares this type in
stdint.h, you should use the thos types instead.
So you program should look like this:
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdint.h>
float average(int n_values, ... )
{
va_list var_arg;
int count;
float sum = 0;
va_start(var_arg, n_values);
for (count = 0; count < n_values; count += 1) {
sum += va_arg(var_arg, uint32_t);
}
va_end(var_arg);
return sum / n_values;
}
int main(void)
{
printf("hello world!\n");
uint32_t t1 = 1;
uint32_t t2 = 4;
uint32_t t3 = 4;
printf("result:%f\n", average(3, t1, t2, t3));
return 0;
}
this is portable and should yield the same results across different
architectures.
I have
typedef union
{
void (*fp1p)(void);
void (*fp2p)(uint32_t);
void (*fp3p)(uint32_t, uint32_t);
void (*fp4p)(uint32_t, uint32_t, uint32_t);
uint32_t (*fp5p)(uint32_t);
uint32_t (*fp6p)(uint32_t, uint32_t);
uint32_t (*fp7p)(uint32_t, uint32_t, uint32_t);
} fp;
struct command
{
char *name; //command name
uint32_t minargs;
uint32_t maxargs;
int minval;
int maxval;
fp read_func_pointer;
fp write_func_pointer;
};
struct command commands[] =
{
[0] = { "reg1001", 0,0,0,0, .read_func_pointer.fp6p = TDC1000_SPIByteReadReg, .write_func_pointer.fp4p = TDC1000_SPIByteWriteReg },
//
//
};
And then
if(condition)
{
uint32_t ret_val = commands[0].read_func_pointer.fp6p(…);
}
else
{
commands[0]. write_func_pointer.fp6p(…);
}
How can I make it generic instead of .fp6p?
I don't know if thats an option for you, but how about adding an enum representing the function pointer type to your struct?
In the conditon statement you could switch on the enum and then call the right function pointer.
I think you may use anonymous members for unions:
struct command
{
char *name; //command name
...
union
{
....
void (*fp4p)(uint32_t, uint32_t, uint32_t);
uint32_t (*fp6p)(uint32_t, uint32_t);
};
...
};
You have to change fp6p, etc. names to fp6pw for write_func members. Then call directly commands[0].fp6p(...). Not sure but initialization must be "generic" as you want.
I'd like to clarify.
Suppose we have several commands
struct command commands[] = {
[0] = { "reg1001", 0,0,0,0, .read_func_pointer.fp6p = TDC1000_SPIByteReadReg, .write_func_pointer.fp4p = TDC1000_SPIByteWriteReg },
[1] = = { "reg7201", 0,0,0,0, .read_func_pointer.fp3p = TDC7200_SPIByteReadReg, .write_func_pointer.fp5p = TDC7200_SPIByteWriteReg },
};
I have a generic function to choose an incoming command
For (i=0; I < sizeof(commands); i++)
{
if (strcmp(commands[i].name,args[0])==0)
{
commands[i]. read_func_pointer.<- Here – how can I know what pointer to place?
}
}
Calling a function of signature known only at runtime is not achievable in portable standard C99 or C11; the signature should be known at compile time (and you could extend your code, conceptually by having a tagged union of function pointers, that is by keeping a tag describing the signature). This is so because the calling conventions can (and do) vary with the function signature (the ABI would use different registers for passing different kinds or types of arguments or results).
Alternatively, consider using libffi; it contains some magic (assembler code, dependent of the ABI), which invokes an arbitrary function pointer whose signature is described by some meta-data.
If you are targetting POSIX, you could use some dlopen & dlsym tricks (you might also consider plugin support in frameworks like Qt5 or POCO or Glib...). You might generate (at runtime) some appropriate (glue) C code in generated-code-001.c, compile it by forking some compiler command (e.g. gcc -Wall -O -fPIC generated-code-001.c -shared -o generated-code-001.so), then dlopen that ./generated-code-001.so shared object (on Linux; on MacOSX the compilation command and the file extension are different), and use dlsym to get the function pointer. I am extensively using such tricks in MELT
I want gcc to optimize away unused function pointers. Ie remove the code completely from the final executable. So far I was not able to achieve this.
Here is updated code:
#include <stdio.h>
struct inner {
void (*fun)(void);
void (*fun2)(void);
};
struct inner2 {
void (*fun)(void);
};
struct foo {
struct inner in;
struct inner2 in2;
};
void lessfun(){
printf("lessfun\n");
}
void morefun(){
printf("morefun\n");
}
const struct foo inst = {
{ .fun = lessfun, .fun2 = morefun },
{ .fun = lessfun }
};
void test(struct foo *f){
f->in.fun();
}
int main(int argc, char *argv){
struct inner2 in = inst.in2;
inst.in.fun();
inst.in.fun2();
in.fun();
/////////////// alt1: nm out | grep morefun -> found
test(&inst);
///////////////
/////////////// alt2: nm out | grep morefun -> not found
struct inner in;
struct inner in2 = inst.in;
in = in2;
test(&in);
///////////////
}
compiler flags: -Os -fdata-sections -Wl,--relax,--gc-sections -ffunction-sections
link flags: -flto -Os -fdata-sections -Wl,--relax,--gc-sections
Compiler: arm-none-eabi-gcc
Here the compiler will include both method1 and method2 into the final program even if they are never used. It is the assignment that seems to make this happen. But if they are never called, it would be nice to completely remove the code to method1 and method2. This obviously happens because technically the function is in fact referenced in the assignment, but since the variable in the assignment is never user it should still be possible to determine that the method is never called.
Do I need to declare it const somehow? How?
How can I have gcc remove the unused functions?
EDIT: I was able to sort of make it work as you see above. But it only works if I do not make a copy of any members of the struct. If a direct copy is made and passed to a function, the compiler fails to optimize unused functions. I'm now 60% certain that this is some kind of optimizer bug.
EDIT2: you may not even reproduce the bug. But here is the scenario that creates it.
struct mydev dev;
struct dev_spi spi;
struct dev_spi sp2 = board.spi0;
sp2.writereadbyte(0);
spi = sp2;
//test(&cpu.spi0);
// using only this call results in correct optimization
// many unused methods pointed to by members of "board" var are gone.
mydev_init(&dev, &spi);
// using this version breaks optimization
// all methods referenced by "board" struct are included in final program
mydev_init(&dev, &sp2);
// this one breaks optimization as well
// same as above.
mydev_init(&dev, &board.spi0);
// there is no difference other than one passes variable directly to the init function
// and the other uses a temp variable.
I'm writing some code which stores some data structures in a special named binary section. These are all instances of the same struct which are scattered across many C files and are not within scope of each other. By placing them all in the named section I can iterate over all of them.
This works perfectly with GCC and GNU ld. Fails on Mac OS X due to missing __start___mysection and __stop___mysection symbols. I guess llvm ld is not smart enough to provide them automatically.
In GCC and GNU ld, I use __attribute__((section(...)) plus some specially named extern pointers which are magically filled in by the linker. Here's a trivial example:
#include <stdio.h>
extern int __start___mysection[];
extern int __stop___mysection[];
static int x __attribute__((section("__mysection"))) = 4;
static int y __attribute__((section("__mysection"))) = 10;
static int z __attribute__((section("__mysection"))) = 22;
#define SECTION_SIZE(sect) \
((size_t)((__stop_##sect - __start_##sect)))
int main(void)
{
size_t sz = SECTION_SIZE(__mysection);
int i;
printf("Section size is %u\n", sz);
for (i=0; i < sz; i++) {
printf("%d\n", __start___mysection[i]);
}
return 0;
}
What is the general way to get a pointer to the beginning/end of a section with FreeBSD linker. Anyone have any ideas?
For reference linker is:
#(#)PROGRAM:ld PROJECT:ld64-127.2
llvm version 3.0svn, from Apple Clang 3.0 (build 211.12)
Similar question was asked about MSVC here: How to get a pointer to a binary section in MSVC?
You can get the Darwin linker to do this for you.
#include <stdio.h>
extern int start_mysection __asm("section$start$__DATA$__mysection");
extern int stop_mysection __asm("section$end$__DATA$__mysection");
// If you don't reference x, y and z explicitly, they'll be dead-stripped.
// Prevent that with the "used" attribute.
static int x __attribute__((used,section("__DATA,__mysection"))) = 4;
static int y __attribute__((used,section("__DATA,__mysection"))) = 10;
static int z __attribute__((used,section("__DATA,__mysection"))) = 22;
int main(void)
{
long sz = &stop_mysection - &start_mysection;
long i;
printf("Section size is %ld\n", sz);
for (i=0; i < sz; ++i) {
printf("%d\n", (&start_mysection)[i]);
}
return 0;
}
Using Mach-O information:
#include <mach-o/getsect.h>
char *secstart;
unsigned long secsize;
secstart = getsectdata("__SEGMENT", "__section", &secsize);
The above gives information about section declared as:
int x __attribute__((section("__SEGMENT,__section"))) = 123;
More information: https://developer.apple.com/library/mac/documentation/developertools/conceptual/machoruntime/Reference/reference.html
Will this code:
inline int funcA(int a) __attribute__((always_inline))
{
return a + 1;
}
inline int funcB(int b) __attribute__((always_inline))
{
return funcA(b + 2);
}
int main()
{
return funcB(3);
}
transformed to code like this?:
int main()
{
return ((3) + 2) + 1;
}
GCC, ARM (iPhone)
Inlining function calls is not something the language requires compilers to do. It's a quality of implementation issue (QoI). But any of GCC, MSVC and clang will do it. Of course, you have to enable optimization.
For instance
# clang++ -cc1 -emit-llvm -O2 -o - main.cpp
define i32 #main() nounwind readnone {
entry:
ret i32 6
}
There are no guarantees when using inline. It serves merely as a hint to the compiler (which in many (not all) cases have more heuristics and better understanding of the impact of inlining than the programmer).
Not necessarily. It depend's on the compiler and settings I guess. In fact in C++ for example it's not even guaranteed that this
inline int funcA(int a)
{
return a + 1;
}
int main()
{
return funcA(3);
}
will get transformed into this
int main()
{
return 3 + 1;
}
inline is just the hint for the compiler. The compiler can ignore it.