Skip to main content
added 149 characters in body
Source Link
Longinus
  • 1.9k
  • 5
  • 22

So how one typically writes a variadic routine is by having a parameter that specifies how many variadic arguments there are and what their types are, and by gently asking that routine's user to get everything right.
printf for instance deduces both arguments' count and types from the format string's specifiers.
[As mentioned by @TobySpeight's comment: Another approach is by requiring a terminating sentinel value, as is used by execl and XtVaSetValues.]

So how one typically writes a variadic routine is by having a parameter that specifies how many variadic arguments there are and what their types are, and by gently asking that routine's user to get everything right.
printf for instance deduces both arguments' count and types from the format string's specifiers.

So how one typically writes a variadic routine is by having a parameter that specifies how many variadic arguments there are and what their types are, and by gently asking that routine's user to get everything right.
printf for instance deduces both arguments' count and types from the format string's specifiers.
[As mentioned by @TobySpeight's comment: Another approach is by requiring a terminating sentinel value, as is used by execl and XtVaSetValues.]

edited body
Source Link
Longinus
  • 1.9k
  • 5
  • 22
typedef struct {
    unsigned int gp_offset;
    ///The element points to the start ofholds the register save area.

  offset in unsignedbytes intfrom fp_offset;reg_save_area
    ///This pointer isto usedthe toplace fetchwhere argumentsthe passednext onavailable thegeneral stack.purpose
    ///It is initialized with the address ofargument theregister firstis argumentsaved.
    ///passed onIn thecase stack,all ifargument any,registers andhave thenbeen alwaysexhausted, updatedit tois
    ///pointset to the start of the nextvalue argument48 on(6 the stack8).

    voidunsigned *overflow_arg_area;int fp_offset;
    ///The element holds the offset in bytes from reg_save_area
    ///to the place where the next available generalfloating purposepoint
    ///argument register is saved.
    ///In case all argument registers have been exhausted, it is
    ///set to the value 48304 (6 ∗ 8 + 16 ∗ 16).

    void *reg_save_area;*overflow_arg_area;
    ///TheThis elementpointer holdsis theused offsetto infetch bytesarguments frompassed reg_save_areaon the stack.
    ///toIt theis placeinitialized wherewith the nextaddress availableof floatingthe pointfirst argument
    ///argumentpassed registeron isthe saved.stack, if any, and then always updated to
    ///Inpoint caseto allthe start of the next argument registerson havethe beenstack.

 exhausted, it is void *reg_save_area;
    ///set toThe theelement valuepoints 304to (6the start 8of +the 16register save 16)area.
} va_list[1];
typedef struct {
    unsigned int gp_offset;
    ///The element points to the start of the register save area.

    unsigned int fp_offset;
    ///This pointer is used to fetch arguments passed on the stack.
    ///It is initialized with the address of the first argument
    ///passed on the stack, if any, and then always updated to
    ///point to the start of the next argument on the stack.

    void *overflow_arg_area;
    ///The element holds the offset in bytes from reg_save_area
    ///to the place where the next available general purpose
    ///argument register is saved.
    ///In case all argument registers have been exhausted, it is
    ///set to the value 48 (6 ∗ 8).

    void *reg_save_area;
    ///The element holds the offset in bytes from reg_save_area
    ///to the place where the next available floating point
    ///argument register is saved.
    ///In case all argument registers have been exhausted, it is
    ///set to the value 304 (6  8 + 16  16).
} va_list[1];
typedef struct {
    unsigned int gp_offset;
    ///The element holds the offset in bytes from reg_save_area
    ///to the place where the next available general purpose
    ///argument register is saved.
    ///In case all argument registers have been exhausted, it is
    ///set to the value 48 (6  8).

    unsigned int fp_offset;
    ///The element holds the offset in bytes from reg_save_area
    ///to the place where the next available floating point
    ///argument register is saved.
    ///In case all argument registers have been exhausted, it is
    ///set to the value 304 (6 ∗ 8 + 16 ∗ 16).

    void *overflow_arg_area;
    ///This pointer is used to fetch arguments passed on the stack.
    ///It is initialized with the address of the first argument
    ///passed on the stack, if any, and then always updated to
    ///point to the start of the next argument on the stack.

    void *reg_save_area;
    ///The element points to the start of the register save area.
} va_list[1];
added 2328 characters in body
Source Link
Longinus
  • 1.9k
  • 5
  • 22

Unlike what some may think, thisThis is actually trivial.
Here is va_list:

  1. Determine whether typetype may be passed in the registers. If not go to step
  2. 53 AMD64 ABI Draft 0.99 7.6 – July 2, 2012 – 17:14
  3. Compute num_gpnum_gp to hold the number of general purpose registers needed to pass typetype and num_fpnum_fp to hold the number of floating point registers needed.
  4. Verify whether arguments fit into registers. In the case: l->gp_offset > 48 − num_gp ∗ 8 or l->fp_offset > 304 − num_fp ∗ 16 go 
    tol->gp_offset > 48 − num_gp ∗ 8
    or
    l->fp_offset > 304 − num_fp ∗ 16
    go to step 7.
  5. Fetch type from l->reg_save_areal->reg_save_area with an offset of l->gp_offsetl->gp_offset and/or l->fp_offsetl->fp_offset. This may require copying to a temporary loca- tion in case the parameter is passed in different register classes or requires an alignment greater than 8 for general purpose registers and 16 for XMM registers.
  6. Set: l->gp_offset = l->gp_offset + num_gp ∗ 8 l->fp_offset = l->fp_offset + num_fp ∗ 16
    l->gp_offset = l->gp_offset + num_gp ∗ 8 l->fp_offset = l->fp_offset + num_fp ∗ 16.
  7. Return the fetched typetype.
  8. Align l->overflow_arg_areal->overflow_arg_area upwards to a 16 byte boundary if align- mentalignment needed by typetype exceeds 8 byte boundary.
  9. Fetch type from l->overflow_arg_areal->overflow_arg_area.
  10. Set l->overflow_arg_areal->overflow_arg_area to: l->overflow_arg_area + sizeof(type)
    l->overflow_arg_area + sizeof(type)
  11. Align l->overflow_arg_areal->overflow_arg_area upwards to an 8 byte boundary.
  12. Return the fetched typetype.

Unlike what some may think, this is actually trivial.
Here is va_list:

  1. Determine whether type may be passed in the registers. If not go to step
  2. 53 AMD64 ABI Draft 0.99.6 – July 2, 2012 – 17:14
  3. Compute num_gp to hold the number of general purpose registers needed to pass type and num_fp to hold the number of floating point registers needed.
  4. Verify whether arguments fit into registers. In the case: l->gp_offset > 48 − num_gp ∗ 8 or l->fp_offset > 304 − num_fp ∗ 16 go to step 7.
  5. Fetch type from l->reg_save_area with an offset of l->gp_offset and/or l->fp_offset. This may require copying to a temporary loca- tion in case the parameter is passed in different register classes or requires an alignment greater than 8 for general purpose registers and 16 for XMM registers.
  6. Set: l->gp_offset = l->gp_offset + num_gp ∗ 8 l->fp_offset = l->fp_offset + num_fp ∗ 16.
  7. Return the fetched type.
  8. Align l->overflow_arg_area upwards to a 16 byte boundary if align- ment needed by type exceeds 8 byte boundary.
  9. Fetch type from l->overflow_arg_area.
  10. Set l->overflow_arg_area to: l->overflow_arg_area + sizeof(type)
  11. Align l->overflow_arg_area upwards to an 8 byte boundary.
  12. Return the fetched type.

This is actually trivial.
Here is va_list:

  1. Determine whether type may be passed in the registers. If not go to step 7.
  2. Compute num_gp to hold the number of general purpose registers needed to pass type and num_fp to hold the number of floating point registers needed.
  3. Verify whether arguments fit into registers. In the case: 
    l->gp_offset > 48 − num_gp ∗ 8
    or
    l->fp_offset > 304 − num_fp ∗ 16
    go to step 7.
  4. Fetch type from l->reg_save_area with an offset of l->gp_offset and/or l->fp_offset. This may require copying to a temporary loca- tion in case the parameter is passed in different register classes or requires an alignment greater than 8 for general purpose registers and 16 for XMM registers.
  5. Set:
    l->gp_offset = l->gp_offset + num_gp ∗ 8 l->fp_offset = l->fp_offset + num_fp ∗ 16.
  6. Return the fetched type.
  7. Align l->overflow_arg_area upwards to a 16 byte boundary if alignment needed by type exceeds 8 byte boundary.
  8. Fetch type from l->overflow_arg_area.
  9. Set l->overflow_arg_area to:
    l->overflow_arg_area + sizeof(type)
  10. Align l->overflow_arg_area upwards to an 8 byte boundary.
  11. Return the fetched type.
added 2328 characters in body
Source Link
Longinus
  • 1.9k
  • 5
  • 22
Loading
added 174 characters in body
Source Link
Longinus
  • 1.9k
  • 5
  • 22
Loading
added 2 characters in body
Source Link
Longinus
  • 1.9k
  • 5
  • 22
Loading
Source Link
Longinus
  • 1.9k
  • 5
  • 22
Loading