Just An Application

October 24, 2014

So Swift Then: Fun With Mangled Names Continued

Continuing where we left off in last week’s thrilling installment, that is, with the encoding of function parameters in mangled function names.

While the return type of a function is necessarily a type and nothing but a type, Swift function parameters come in a variety of different flavours.

Some of these flavours affact how a function is called and what it can be called with.

Mangled function names are potentially used by the linker so the names must include an encoding of the relevant information about the function parameters which affect how the function can be called.

A basic vanilla function parameter is of the form

    'name' ":" 'type'

for example

    func cod(b: Bool)

In the case of a vanilla parameter only the type is significant so we would expect that the parameter would appear in a mangled function name as the encoding of its type.

A vanilla parameter can be augmented with an ‘external name’ which is declared before the ‘name’, for example

    func cod(e b: Bool)

The ‘external name’ must appear in any call to the function, for example

    cod(e: true)

In this case, since the external name is significant, we would expect both it and the type to appear in a mangled function name is some way.

By default function parameters are immutable. A function parameter can be made mutable using the

    var

keywood. for example

    func cod(var b: Bool)

The fact that a parameter of a function is mutable is not apparent to a caller of that function, consequently we would not expect the encoding of a mutable parameter to be any different from that of an immutable one.

A function parameter can be made mutable such that changes to it are visible to the caller using the

    inout

keywood. for example

    func cod(inout b: Bool)

A call to this function would look like this

    cod(&flag)

and flag must be mutable.

In this case we would expect the encoding to comprise the encoding of the parameter type plus something to indicate that it is an inout parameter.

A vanilla parameter can have a default value added, like so

    func cod(b: Bool = true)

A parameter with a default value must have an ‘external name’. If it does not have an explicit one, the ‘name’ is also used as the ‘external name’.

A call to the function above with a value would look like this

    cod(b:true)

and without one, so the default value is used, like this

    cod()

While the presence of a default value does affect how the function can be called, the effect is to define a function with two different entry points.

It is easier for the compiler to handle this by generating what looks like two different functions than for the linker to edit compiled code at the call site.

Hence, in this case we would only expect the ‘external name’ and the parameter type to appear in the parameter encoding.

A Swift function can be defined to take a variable number of parameters lke so

    func cod(flags: Bool...)

In the body of the function

   flags

has the type

   [Bool]

One candidate for the encoding of this kind of parameter would be the encoding of the appropriate array type.

Vanilla Parameters

Compiling

    func cod(b: Bool)
    {
    }

gives us the symbol

    __TF4xper3codFSbT_

Compiling

    func cod(b: Bool, c: Bool)
    {
    }

gives us the symbol

    __TF4xper3codFTSbSb_T_

Compiling

    func cod(b: Bool, c: Bool, d: Bool)
    {
    }

gives us the symbol

    __TF4xper3codFTSbSbSb_T_

On the basis of these three examples so far we can infer the following rules for the encoding of the parameters of a function with N vanilla parameters.

If N == 0 the parameters are represented by the encoding of the empty tuple type

   ()

If N == 1 the parameters are represented by the encoding of

    T

where T is the type of the single parameter.

If N > 1 then the parameters are represented by the encoding of the tuple type

   (T[0], ..., T[N-1])

where T[i] is the type of the i'th parameter.

As it stands the N == 1 case is a bit odd. Why is it a special case ? What if the single parameter has a tuple type ?

Compiling this

    func cod(b: (Bool))
    {
    }

gives us the symbol

    __TF4xper3codFSbT_

NOT

    __TF4xper3codFTSb_T_

which is surprising but it does mean that the rule for N == 1 holds.

Compiling this

    func cod(b: (Bool,Bool))
    {
    }

gives us the symbol

    __TF4xper3codFTSbSb_T_

which is even more surprising.

Two functions with different numbers of parameters end up with the same mangled name.

That cannot be right.

How can you have both of the functions in the same library ?

What happens if you compile both of them in the same file ?

    $ swiftc -module-name xper -emit-library funcs.swift
    Basic Block in function '_TF4xper3codFTSbSb_T_' does not have terminator!
    label %entry1
    LLVM ERROR: Broken function found, compilation aborted!

That's not good.

What about putting them in different files ?

    $ swiftc -module-name xper -emit-library func01.swift func02.swift
    duplicate symbol __TF4xper3codFTSbSb_T_ in:
        [..]/func01-b2b04f.o
        [..]/func02-5b9bf6.o
    ld: 1 duplicate symbol for architecture x86_64
    <unknown>:0: error: linker command failed with exit code 1 (use -v to see invocation)

That's not good either.

OK, them's the rules and they are broken.

Sidles away nonchalantly, hands in pockets, hoping no one is going to ask him to pay for the damage.

Parameter Type Substitution Syntax

There is one slight twist with the encoding of function parameter types even in the all vanilla parameters case.

Compiling

    func cod(c1: Character, c2: Character)
    {
    }

gives us the symbol

    __TF4xper3codFTOSs9CharacterS0__T_

rather than

    __TF4xper3codFTOSs9CharacterOSs9CharacterST_

If we read

    S0_

as substitute the 0th parameter type then it makes sense.

External Names

Adding an external name to our first example

    func cod(e b: Bool)
    {
    }

and compiling gives us the symbol

    __TF4xper3codFT1eSb_T_

We now have the function's parameters represented by

    T1eSb_

which looks like the encoding of the named tuple type

    (e:Bool)

Adding external names to our second example

    func cod(e b: Bool, f c: Bool)
    {
    }

and compiling gives us the symbol

    __TF4xper3codFT1eSb1fSb_T_

and we now have the function's parameters represented by an encoding of the named tuple type

    (e:Bool, f:Bool)

Adding external names to the first two parameters of our third example

    func cod(e b: Bool, f c: Bool, d: Bool)
    {
    }

and compiling gives us the symbol

    __TF4xper3codFT1eSb1fSbSb_T_

and we now have the function's parameters represented by an encoding of the hybrid named/unnamed tuple type

    (e:Bool, f:Bool, Bool)

as you might expect.

Mutable Parameters

Modifying our first example once more

    func cod(var b: Bool)
    {
    }

and compiling gives us the symbol

    __TF4xper3codFSbT_

as expected the presence of the var keyword has no effect on the encoding of the paramater.

inout Parameters

Compiling

    func cod(inout b: Bool)
    {
    }

gives us the symbol

    __TF4xper3codFRSbT_

and

    RSb

for the encoding of the parameter with an

    R

for 'Reference' or 'Recondite' or something.

An inout parameter can have an 'external name'.

Compiling

    func cod(inoute b: Bool)
    {
    }

gives us the symbol

    __TF4xper3codFT1eRSb_T_

and

    T1eRSb_

for the encoding of the parameter.

Default Values

Compiling

    func cod(b: Bool = true)
    {
    }

gives us the symbol

    __TF4xper3codFT1bSb_T_

and a second symbol

    __TIF4xper3codFT1bSb_T_A_

The first symbol is the same as the symbol for the function

    func cod(b b: Bool)
    {
    }

and would enable the linker to identify the entry point for calls to the function made with a value.

The second symbol presumably enables the linker to identify the entry point for the calls to the function made without a value.

Adding another parameter

    func cod(s:String, b: Bool = true)
    {
    }

and compiling gives us the two symbols

    __TF4xper3codFTSS1bSb_T_

and

    __TIF4xper3codFTSS1bSb_T_A0_

because there are still only two ways to call the function, for example

    cod("")

and

    cod("", b:false)

Compiling a function with two parameters both with default values

    func cod(i:Int = 2, b: Bool = true)
    {
    }

and compiling gives us three symbols

    __TF4xper3codFT1iSi1bSb_T_
    __TIF4xper3codFT1iSi1bSb_T_A0_
    __TIF4xper3codFT1iSi1bSb_T_A_

as there are three ways to call the function.

In all these examples it looks as though it is the 'A' suffix on the 'secondary' symbols which identifies the parameter value or values which are being defaulted.

Varadic Parameters

Compiling

    func cod(flags: Bool...)
    {
    }

gives us the symbol

    __TF4xper3codFtGSaSb__T_

and

   tGSaSb__

for the encoding of the parameter.

We have

   GSaSb_

for

  [Bool]

but 't' rather than 'T' for the tuple.

Adding another parameter

    func  cod(s: String, flags:  Bool...)
    {
    }

and compiling gives us the symbol

    __TF4xper3codFtSSGSaSb__T_

A varadic parameter can have an 'external name'

    func  cod(flags f:  Bool...)
    {
    }

Compiling this gives us the symbol

    __TF4xper3codFt5flagsGSaSb__T_

The 'external name' is now present as we would expect.

In all these examples the 't' remains resolutely lower-case so it looks as though it is connected with the presence of the varadic parameter.

Not The Summary

This is another post that is now way too long so its time to call a halt.

Coming up next time, what has the function name mangling machine got against single element type tuples ?


Copyright (c) 2014 By Simon Lewis. All Rights Reserved.

Unauthorized use and/or duplication of this material without express and written permission from this blog's author and owner Simon Lewis is strictly prohibited.

Excerpts and links may be used, provided that full and clear credit is given to Simon Lewis and justanapplication.wordpress.com with appropriate and specific direction to the original content.

Advertisements

Leave a Comment »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Create a free website or blog at WordPress.com.

%d bloggers like this: