【问题标题】:Getting Segmentation fault at RET在 RET 出现分段错误
【发布时间】:2018-03-29 23:16:58
【问题描述】:

我有以下头文件:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <assert.h>
#include <stdbool.h>
/**  **/

// size: 1B
typedef enum string_proc_func_type_t{
    REVERSIBLE      = 0,
    IRREVERSIBLE    = 1
} __attribute__((__packed__)) string_proc_func_type;


// size: 12B
typedef struct string_proc_key_t {
    uint32_t length; // 4B
    char* value; // 8B (ptr)
} __attribute__((__packed__)) string_proc_key; 
typedef void (*string_proc_func) (string_proc_key*);

// size 24B
typedef struct string_proc_list_t {
    char* name; // 8B (ptr)
    struct string_proc_node_t* first; // 8B (ptr)
    struct string_proc_node_t* last; // 8B (ptr)
} __attribute__((__packed__)) string_proc_list;

// size 33B
typedef struct string_proc_node_t {
    struct string_proc_node_t* next; // 8B (ptr)
    struct string_proc_node_t* previous; // 8B (ptr)
    string_proc_func f; // 8B (ptr)
    string_proc_func g; // 8B (ptr)
    string_proc_func_type type; // 1B
} __attribute__((__packed__)) string_proc_node;

string_proc_list* string_proc_list_create(char* name);
void string_proc_list_destroy(string_proc_list* list);

// Aux functions
uint32_t str_len(char* a);
char* str_copy(char* a);

我已经实现了如下的辅助功能:

uint32_t str_len(char* a) { 
    uint32_t cont = 0;
    while(a != NULL && *a != '\0') {
        cont++;
        a++;
    }
    return cont;
}

char* str_copy(char* a) { 
    uint32_t length = str_len(a);
    char* copy = malloc(length);
    for (uint32_t i = 0; i < length; ++i) {
        copy[i] = a[i];
    }
    return copy;
}

现在我想在 Assembly 上实现 string_proc_list_create 函数,我最终得到了这个:

; C functions
    extern malloc
    extern free
    extern fopen
    extern fclose
    extern fprintf
    extern str_copy

; structs sizes
    %define STRUCT_STRING_PROC_LIST_SIZE 24

; structs offsets
    %define STRUCT_STRING_PROC_LIST_NAME_OFFSET 0
    %define STRUCT_STRING_PROC_LIST_FIRST_OFFSET 8
    %define STRUCT_STRING_PROC_LIST_LAST_OFFSET 16
section .data


section .text

global string_proc_list_create
string_proc_list_create:
    push rbp
    mov rbp, rsp

    push rdi ; save ptr to name

    ; allocate mem for struct
    mov rdi, STRUCT_STRING_PROC_LIST_SIZE
    sub rsp, 8 ; align stack
    call malloc
    add rsp, 8 ; unalign stack
    ; get ptr to struct at RAX

    pop rdi ; get ptr to name en RDI

    ; save ptr to struct at RBX 
    push rbx 
    mov rbx, rax

    ; copy name
    add rsp, 8 ; align stack
    call str_copy
    add rsp, 8 ; unalign stack
    ; get ptr to name (copy) at RAX

    ; initialize struct (ptr to struct at RBX, ptr to name (copy) at RAX)
    mov qword [rbx + STRUCT_STRING_PROC_LIST_NAME_OFFSET], rax
    mov qword [rbx + STRUCT_STRING_PROC_LIST_FIRST_OFFSET], 0
    mov qword [rbx + STRUCT_STRING_PROC_LIST_LAST_OFFSET], 0

    pop rbx
    pop rbp
    ret

然后,我尝试执行这一行:

string_proc_list* list =  string_proc_list_create("aName");

但我在 RET 遇到了分段错误。我认为我可能破坏了堆栈框架,但我找不到我的代码有什么问题。有什么帮助吗?

【问题讨论】:

  • call str_copy 之前有一个add 而不是sub。学习使用调试器。
  • 哇。我调试了,我没有看到。非常抱歉,谢谢!
  • 您使用str_copy() 创建的字符串没有空终止符。
  • 在调用malloc时,你必须给str_len(a)加1。并在循环后附加一个空字符。
  • POSIX 有一个内置函数 strdup() 可以做到这一点。

标签: c assembly segmentation-fault 64-bit


【解决方案1】:

问题不在于您发布的代码,这是完全正确的(如果您所说的就是您的意思),但很可能是您使用str_copy 的地方。问题是您得到的字符串不是以空字符结尾的字符串。你

uint32_t length = str_len(a);
char* copy = malloc(length);

当您必须 malloc(length+1); 以允许最终的 \0 字符时。 然后,您将原始字符串中的精确长度字符复制到副本中。然后你应该在字符串中添加一个最终的\0 char,这样就完成了。

您的代码没有问题,但它生成的不是字符串,而是包含原始字符串有价值内容的 char 数组。要使其成为正确的字符串,您需要为空字符获取空间,并将其添加到字符串中,如下所示:

char* str_copy(char* a) { 
    uint32_t length_plus_1 = str_len(a) + 1; // enough for null to be included
    char* copy = malloc(length_plus_1);
    for (uint32_t i = 0; i < length_plus_1; ++i) {
        copy[i] = a[i];
    }
    return copy;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多