Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Contiguous memory guarantees with C++ function parameters

Appel [App02] very briefly mentions that C (and presumably C++) provide guarantees regarding the locations of actual parameters in contiguous memory as opposed to registers when the address-of operator is applied to one of formal parameters within the function block.

e.g.

void foo(int a, int b, int c, int d)
{
    int* p = &a;
    for(int k = 0; k < 4; k++)
    {
       std::cout << *p << " ";
       p++;
    }
    std::cout << std::endl;
}

and an invocation such as...

foo(1,2,3,4);

will produce the following output "1 2 3 4"

My question is "How does this interact with calling conventions?"

For example __fastcall on GCC will try place the first two arguments in registers and the remainder on the stack. The two requirements are at odds with each other, is there any way to formally reason about what will happen or is it subject to the capricious nature of implementation defined behaviour?

[App02] Modern Compiler Implementation in Java, Andrew w. Appel, Chapter 6, Page 124

Update: I suppose that this question is answered. I think I was wrong to base the whole question on contiguous memory allocation when what I was looking for (and what the reference speaks of) is the apparent mismatch between the need for parameters being in memory due the use of address-of as opposed to in registers due to calling conventions, maybe that is a question for another day.

Someone on the internet is wrong and sometimes that someone is me.

like image 510
DuncanACoulter Avatar asked Mar 29 '11 11:03

DuncanACoulter


3 Answers

First of all your code doesn't always produce 1, 2, 3, 4. Just check this one: http://ideone.com/ohtt0 Correct code is at least like this:

void foo(int a, int b, int c, int d)
{
    int* p = &a;
    for (int i = 0; i < 4; i++)
    {
        std::cout << *p;
        p++;
    }
}

So now let's try with fastcall, here:

void __attribute__((fastcall)) foo(int a, int b, int c, int d)
{
    int* p = &a;
    for (int i = 0; i < 4; i++)
    {
        std::cout << *p << " ";
        p++;
    }
}

int main()
{
        foo(1,2,3,4);
}

Result is messy: 1 -1216913420 134514560 134514524

So I really doubt that something can be guaranteed here.

like image 193
Andrey Avatar answered Oct 11 '22 07:10

Andrey


The C++ standard has no concept of a calling convention. That's left for the compiler to deal with.

In this case, if the standard requires that parameters be contiguous when the address-of operator is applied, there's a conflict between what the standard requires of your compiler and what you require of it.

It's up to the compiler to decide what to do. I'd think most compilers would give your requirements priority over the standard's, however.

like image 23
Collin Dauphinee Avatar answered Oct 11 '22 08:10

Collin Dauphinee


There is nothing in the standard about calling conventions or how parameters are passed.

It is true that if you take the address of one variable (or parameter) that one has to be stored in memory. It doesn't say that the value cannot be passed in a register and then stored to memory when its address is taken.

It definitely doesn't affect other variables, who's addresses are not taken.

like image 44
Bo Persson Avatar answered Oct 11 '22 07:10

Bo Persson