Почему syscall abi golang clone отличается от клона ядра Linux на x86-64

Вы могли бы найти bindParam, когда вы просто хотите привязать ссылку на переменную к параметру в запросе, но, возможно, еще нужно сделать некоторые манипуляции на нем и только хотите, чтобы значение переменной вычислялось во время выполнения запроса , Он также позволяет выполнять более сложные вещи, такие как привязка параметра к вызову хранимой процедуры и добавление возвращаемого значения в связанную переменную.

Подробнее см. Документацию bindParam , документация bindValue и выполнить документацию .

Например,

$col1 = 'some_value';
$pdo->bindParam(':col1', $col1);
$col1 = 'some_other_value';
$pdo->execute(); // would use 'some_other_value' for ':col1' parameter

bindValue и передача массива в execute ведут себя так же, как значение параметра фиксировано в этой точке, и SQL выполняется соответствующим образом.

Следуя тому же примеру выше, но используя bindValue

$col1 = 'some_value';
$pdo->bindValue(':col1', $col1);
$col1 = 'some_other_value';
$pdo->execute(); // would use 'some_value' for ':col1' parameter

Когда передавая значения непосредственно в execute, все значения рассматриваются как строки (даже если задано целочисленное значение). Поэтому, если вам нужно применять типы данных, вы всегда должны использовать bindValue или bindParam.

Я думаю, вы могли бы видеть, что bind* используется больше, чем execute(array), поскольку многие считают, что это лучшее кодирование практика для явного определения типов данных в объявлениях параметров.

5
задан api 2 March 2019 в 16:27
поделиться

1 ответ

Причина, по которой DX и R10 равны нулю

В соответствии с man-страницей клона , они используются, только когда установлены CLONE_PARENT_SETTID, CLONE_CHILD_SETTID.

CLONE_PARENT_SETTID (начиная с Linux 2.5.49) Сохраните идентификатор дочернего потока в месте ptid в памяти родителя. (В Linux 2.5.32-2.5.48 был флаг CLONE_SETTID, который сделал это.) Операция сохранения завершается до того, как clone () возвращает управление в пространство пользователя.

CLONE_CHILD_SETTID (начиная с Linux 2.5.49) Сохраните идентификатор дочернего потока в месте ctid в памяти дочернего элемента. Операция сохранения завершается до того, как clone () вернет управление в пространство пользователя.

DX и R10 соответствуют ptid и ctid в этой справочной странице ( Ссылка ).

На самом деле этот флаг не устанавливается при вызове runtime.clone () из os_linux.go: Source .

Причина, по которой им не нужен tid, может быть в том, что это не библиотека типа pthread, в которой пользователь делает что-то сложное, используя tid.

Что R8, R9 и R12 используются для

Вкратце, R8, R9 и R12 не используются системным вызовом, но используются для построения стека после него.

Обратите внимание, что R8 и R9 передаются в качестве аргумента системному вызову, но не используются клоном (см. Причину ниже), и R12 сохраняется после системного вызова, эти регистры безопасно использовать после системного вызова. ( Ссылка )

Посмотрим подробнее.

внутренне runtime.clone вызывается следующим образом: Источник

func newosproc(mp *m) {
    stk := unsafe.Pointer(mp.g0.stack.hi)
    ....
    ret := clone(cloneFlags, stk, unsafe.Pointer(mp), unsafe.Pointer(mp.g0), unsafe.Pointer(funcPC(mstart)))
    ....
}

Чтение Краткое руководство по ассемблеру Go и опубликованный код OP, вы можете видеть, что R8 - это указатель на mp, а R9 - это указатель на mp.g0, а R12 - это указатель на некоторую функцию, которую вы хотите вызвать в потоке clone ed. (структура m и g выглядит следующим образом: Источник и это: Источник ).

R8 является аргументом клонирования, который указывает tls (локальное хранилище потока), но он не используется, если не установлено CLONE_SETTLS: Источник

R9 обычно используется в качестве 6-го аргумента для системный вызов, но клон не использует его, потому что он использует только 5 аргументов ( Источник ).

R12 - это регистр, который сохраняется после системного вызова.

Итак, наконец, давайте посмотрим на источник runtime.clone. Важная вещь после SYSCALL. Они делают некоторую настройку стека, используя R8 и R9 в дочернем потоке, который создается, и, наконец, вызывают R12.

// int32 clone(int32 flags, void *stk, M *mp, G *gp, void (*fn)(void));
TEXT runtime·clone(SB),NOSPLIT,[111]
    MOVL    flags+0(FP), DI
    MOVQ    stk+8(FP), SI
    MOVQ    [111], DX
    MOVQ    [111], R10

    // Copy mp, gp, fn off parent stack for use by child.
    // Careful: Linux system call clobbers CX and R11.
    MOVQ    mp+16(FP), R8
    MOVQ    gp+24(FP), R9
    MOVQ    fn+32(FP), R12

    MOVL    $SYS_clone, AX
    SYSCALL

    // In parent, return.
    CMPQ    AX, [111]
    JEQ 3(PC)
    MOVL    AX, ret+40(FP)
    RET

    // In child, on new stack.
    MOVQ    SI, SP

    // If g or m are nil, skip Go-related setup.
    CMPQ    R8, [111]    // m
    JEQ nog
    CMPQ    R9, [111]    // g
    JEQ nog

    // Initialize m->procid to Linux tid
    MOVL    $SYS_gettid, AX
    SYSCALL
    MOVQ    AX, m_procid(R8)

    // Set FS to point at m->tls.
    LEAQ    m_tls(R8), DI
    CALL    runtime·settls(SB)

    // In child, set up new stack
    get_tls(CX)
    MOVQ    R8, g_m(R9)
    MOVQ    R9, g(CX)
    CALL    runtime·stackcheck(SB)

nog:
    // Call fn
    CALL    R12

//(omitted)
0
ответ дан ymonad 2 March 2019 в 16:27
поделиться
Другие вопросы по тегам:

Похожие вопросы: