5

いくつかの割り当てを使用して、いくつかの OS の基礎を理解しようとしています。私はすでに同様の質問を投稿しており、満足のいく回答を得ています。しかし、これは少し異なりますが、デバッグできませんでした。だからここに私がすることがあります:

私がやりたいことは、メイン プログラムを開始し、スペースを malloc し、それをスタックとして使用してユーザー レベルのスレッドを開始することです。私の問題は、返送先住所にあります。これまでのコードは次のとおりです。

[コードを編集して、現在の回答の状態に更新しています]

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#define STACK_SIZE 512

void switch_thread(int*,int*);

int k = 0;

void simple_function()
{
    printf("I am the function! k is: %d\n",k);
    exit(0);
}

void create_thread(void (*function)())
{   
   int* stack = malloc(STACK_SIZE + 32);
   stack = (int* )(((long)stack & (-1 << 4)) + 0x10);
   stack = (int* ) ((long)stack + STACK_SIZE); 
   *stack = (long) function;
   switch_thread(stack,stack);  
}

int main()
{
    create_thread(simple_function);
    assert(0);
    return 0;
}

switch_thread は、次のように記述したアセンブリ コードです。

.text
    .globl  switch_thread
switch_thread:  
    movq    %rdi, %rsp
    movq    %rsi, %rbp
    ret

このコードは GDB の下で非常にうまく動作し、期待される出力を提供します (つまり、制御を simple_function に渡し、「I am the function! k is: 0」と出力します)。しかし、個別に実行すると、セグメンテーション違反が発生します。困惑しています。この結果によって。

どんな助けでも大歓迎です。前もって感謝します。

4

2 に答える 2

7

コードに関する 2 つの問題:

  1. スレッドが実際に適切なプロシージャ (またはネストされたプロシージャ) 内にない限り、「ベース ポインター」などはありません。これにより、スレッドは初期化の時点で特定のプロシージャ内にないため、%rbp の値は無関係になります。

  2. あなたの考えに反して、ret命令が実行されると、%rsp が参照している値がプログラム カウンターの新しい値になります。これは、実行時に の代わりに*(base_pointer + 1),*(base_pointer)が参照されることを意味します。ここでも、%rbp の値は関係ありません。

コード (実行するための最小限の変更) は次のようになります。

void switch_thread(int* stack_pointer,int* entry_point);

void create_thread(void (*function)())
{
    int* stack_pointer = malloc(STACK_SIZE + 8);
    stack_pointer += STACK_SIZE; //you'd probably want to back up the original allocated address if you intend to free it later for any reason.
    switch_thread(stack_pointer,function);      
}

switch_thread ルーチンは次のようになります。

    .text
    .globl  switch_thread
switch_thread:
    mov     %rsp, %rax //move the original stack pointer to a scratch register
    mov     %rdi, %rsp //set stack pointer
    push    %rax       //back-up the original stack pointer
    call    %rsi       //call the function
    pop     %rsp       //restore the original stack pointer
    ret                //return to create_thread

参考までに: 自分でスレッドを初期化する場合は、最初にスレッド エントリ ポイントとして機能する適切なトランポリンを作成することをお勧めします (例: ntdll の RtlUserThreadStart)。これにより、特にプログラムをマルチスレッド化し、パラメーターを開始ルーチンに渡したい場合に、物事がより明確になります。

于 2013-04-22T17:36:23.750 に答える