amd64/124134: The kernel doesn't follow the calling convention in the SVR4/i386 ABI

Pedro F. Giffuni pfgshield-freebsd at
Fri May 30 14:10:04 UTC 2008

>Number:         124134
>Category:       amd64
>Synopsis:       The kernel doesn't follow the calling convention in the SVR4/i386 ABI
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-amd64
>State:          open
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Fri May 30 14:10:03 UTC 2008
>Originator:     Pedro F. Giffuni
>Release:        6.3-Release
FreeBSD 6.3-RELEASE FreeBSD 6.3-RELEASE #10: Sat Jan 19 01:13:55 COT 2008     root at  amd64

While porting glibc to FreeBSD it was found that FreeBSD doesn't strictly conform to the SVR4 ABI on AMD64: (see startup calling convention in 3.4.1.)

Further explanation from Petr Salinger:

/* This is the canonical entry point, usually the first thing in the text
    segment.  The SVR4/i386 ABI (pages 3-31, 3-32) says that when the entry
    point runs, most registers' values are unspecified, except for a few.
    Blindly applied on amd64:

    %rdx         Contains a function pointer to be registered with `atexit'.
                 This is how the dynamic linker arranges to have DT_FINI
                 functions called for shared libraries that have been loaded
                 before this code runs.

    %rsp         The stack contains the arguments and environment:
                 0(%rsp)                 argc
                 8(%rsp)                 argv[0]
                 (8*argc)(%rsp)          NULL
                 (8*(argc+1))(%rsp)      envp[0]

    But on amd64 %rsp also have to be 16-byte aligned,
    standard C calling convention already passes arguments in registers.

    FreeBSD uses %edi as pointer to arguments and environment, %rsp is passed aligned.
    On entry from kernel, %rsp=%rdi or %rsp=%rdi-8,
    on entry from, glibc might set up it slightly differently.

    On FreeBSD, we use %rsi for passing function pointer to rtld_fini().
    On entry from FreeBSD kernel, %rsi is cleared, %rdx is not cleared,
    on entry from, glibc sets both %rsi and %rdx to point to rtld_fini().

    Used interface (via %rdi, %rsi) is equal to standard C calling interface for

    void _start(void *arg, void *rtld_fini());

It can be workaround in FreeBSD kernel by following both standards simultaneously,
i.e. on entry from kernel after exec() should be %rsp=%rdi and %rdx=%rsi, and %rsp should be properly aligned.


More information about the freebsd-amd64 mailing list