Omnifarious

ChatGPT transcript trying to get it to generate inline assembly

Dec 8th, 2022
51
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Markdown 8.21 KB | Software | 0 0

Me:

Please write commented C++ for a generic system call interface for Linux on x86_64 that uses inline assembly.

ChatGPT:

Here is an example of a generic system call interface for Linux on x86_64 that uses inline assembly:

#include <stdint.h>

// Define the system call number for the syscall we want to make
#define SYS_CALL_NUMBER 0

// Define the inline assembly to make the syscall
inline void syscall(uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t syscall_number) {
    // Inline assembly to make the syscall
    asm volatile (
        // Move the syscall number into the rax register
        "mov %[syscall_number], %%rax;"

        // Move the arguments into the appropriate registers
        "mov %[arg1], %%rdi;"
        "mov %[arg2], %%rsi;"
        "mov %[arg3], %%rdx;"
        "mov %[arg4], %%r10;"

        // Make the syscall
        "syscall;"

        // Outputs
        :
        // Inputs
        : [syscall_number] "r" (syscall_number),
          [arg1] "r" (arg1),
          [arg2] "r" (arg2),
          [arg3] "r" (arg3),
          [arg4] "r" (arg4)
    );
}

// Example usage of the syscall function
int main() {
    // Make the syscall with the desired arguments
    syscall(0, 0, 0, 0, SYS_CALL_NUMBER);

    return 0;
}

In this example, we define a macro called SYS_CALL_NUMBER that specifies the system call number for the syscall we want to make. Then, we define an inline function called syscall that takes the arguments for the syscall and the syscall number as inputs.

Inside the syscall function, we use inline assembly to move the syscall number into the rax register, and move the syscall arguments into the appropriate registers (rdi, rsi, rdx, and r10). Then, we make the syscall using the syscall instruction.

The syscall function can be used in the same way as any other C++
function, as shown in the main function. You just need to specify the
arguments for the syscall and the syscall number, and the function will
make the syscall for you.

Me:

That answer is in C, please re-write it to use modern C++.

ChatGPT:

Here is an example of a generic system call interface for Linux on x86_64 that uses inline assembly in modern C++:

#include <cstdint>

// Define the system call number for the syscall we want to make
constexpr uint64_t SYS_CALL_NUMBER = 0;

// Define the inline assembly to make the syscall
[[noreturn]] inline void syscall(uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t syscall_number) {
    // Inline assembly to make the syscall
    asm volatile (
        // Move the syscall number into the rax register
        "mov %[syscall_number], %%rax;"

        // Move the arguments into the appropriate registers
        "mov %[arg1], %%rdi;"
        "mov %[arg2], %%rsi;"
        "mov %[arg3], %%rdx;"
        "mov %[arg4], %%r10;"

        // Make the syscall
        "syscall;"

        // Outputs
        :
        // Inputs
        : [syscall_number] "r" (syscall_number),
          [arg1] "r" (arg1),
          [arg2] "r" (arg2),
          [arg3] "r" (arg3),
          [arg4] "r" (arg4)
    );

    // This function never returns
    __builtin_unreachable();
}

// Example usage of the syscall function
int main() {
    // Make the syscall with the desired arguments
    syscall(0, 0, 0, 0, SYS_CALL_NUMBER);

    return 0;
}

In this example, we define a constexpr variable called SYS_CALL_NUMBER that specifies the system call number for the syscall we want to make. Then, we define an inline function called syscall that takes the arguments for the syscall and the syscall number as inputs.

Inside the syscall function, we use inline assembly to move the syscall number into the rax register, and move the syscall arguments into the appropriate registers (rdi, rsi, rdx, and r10). Then, we make the syscall using the syscall instruction. We also mark the function as [[noreturn]] to indicate that it never returns.

The syscall function can be used in the same way as any other C++
function, as shown in the main function. You just need to specify the
arguments for the syscall and the syscall number, and the function will
make the syscall for you.

Me:

That's a little better. Here is a better example of how to do this that is missing comments. The C++ code starts with "----CUT HERE----" and also ends with "----CUT HERE----".

----CUT HERE----

#include <cstdint>

enum class call_id : ::std::uint16_t;
using val_t = ::std::int64_t;

struct syscall_param {
   syscall_param(val_t v) noexcept : value(v) { } // NOLINT
   // NOLINTNEXTLINE
   syscall_param(void *v) noexcept : value(reinterpret_cast<val_t>(v)) {
      static_assert(sizeof(void *) == sizeof(val_t));
   }
   // NOLINTNEXTLINE
   syscall_param(void const *v) noexcept : value(reinterpret_cast<val_t>(v)) {
      static_assert(sizeof(void *) == sizeof(val_t));
   }
   val_t value;
};

inline val_t do_syscall(call_id callnum,
                           syscall_param const &p1,
                           syscall_param const &p2,
                           syscall_param const &p3,
                           syscall_param const &p4,
                           syscall_param const &p5,
                           syscall_param const &p6) noexcept
{
   val_t retval;
   register volatile val_t rp4 asm ("r10") = p4.value;
   register volatile val_t rp5 asm ("r8") = p5.value;
   register volatile val_t rp6 asm ("r9") = p6.value;
   asm volatile (
      "syscall\n\t"
      :"=a"(retval)
      :"a"(static_cast<::std::uint64_t>(callnum)), "D"(p1.value), "S"(p2.value), "d"(p3.value), "r"(rp4), "r"(rp5), "r"(rp6)
      :"%rcx", "%r11", "memory"
      );
   return retval;
}

----CUT HERE----

Please add comments.

ChatGPT:

Here is the modified code with comments added:

#include <cstdint>

// Define an enum class called call_id that represents syscall numbers
enum class call_id : ::std::uint16_t;

// Define a type called val_t that represents a syscall argument
using val_t = ::std::int64_t;

// Define a struct called syscall_param that can be used to wrap syscall arguments
struct syscall_param {
   // Construct a syscall_param from a value_t
   syscall_param(val_t v) noexcept : value(v) { } // NOLINT

   // Construct a syscall_param from a pointer
   // NOLINTNEXTLINE
   syscall_param(void *v) noexcept : value(reinterpret_cast<val_t>(v)) {
      static_assert(sizeof(void *) == sizeof(val_t));
   }

   // Construct a syscall_param from a const pointer
   // NOLINTNEXTLINE
   syscall_param(void const *v) noexcept : value(reinterpret_cast<val_t>(v)) {
      static_assert(sizeof(void *) == sizeof(val_t));
   }

   // The wrapped syscall argument
   val_t value;
};

// Define a function that makes a syscall with up to six arguments
inline val_t do_syscall(call_id callnum,
                           syscall_param const &p1,
                           syscall_param const &p2,
                           syscall_param const &p3,
                           syscall_param const &p4,
                           syscall_param const &p5,
                           syscall_param const &p6) noexcept
{
   // Define a variable to hold the return value of the syscall
   val_t retval;

   // Move the fourth, fifth, and sixth syscall arguments into registers
   register volatile val_t rp4 asm ("r10") = p4.value;
   register volatile val_t rp5 asm ("r8") = p5.value;
   register volatile val_t rp6 asm ("r9") = p6.value;

   // Inline assembly to make the syscall
   asm volatile (
      "syscall\n\t" // Make the syscall
      :"=a"(retval) // Output: return value in rax
      :"a"(static_cast<::std::uint64_t>(callnum)), // Input: syscall number in rax
        "D"(p1.value), // Input: first argument in rdi
        "S"(p2.value), // Input: second argument in rsi
        "d"(p3.value), // Input: third argument in rdx
        "r"(rp4), // Input: fourth argument in r10
        "r"(rp5), // Input: fifth argument in r8
        "r"(rp6) // Input: sixth argument in r9
      :"%rcx", "%r11", "memory" // Clobbered registers
      );

   // Return the syscall return
Tags: chatGPT
Add Comment
Please, Sign In to add comment