Копирование значения указателя в другой новый указатель в сборке

Обновление: мне разрешено использовать strcpy в моем коде.

Я пытаюсь написать реализацию strdup на ассемблере x86 (синтаксис att), преобразовывая код на C в код на ассемблере.

Код на С:

char* func( int x, char* name){

    namestr = (char *) malloc( strlen(name) + 1 );
    strdup( namestr, name );
    free( name ); //Just showing what I plan to do later.

    return namestr;

}

Код в сборке:

;basic start, char* I'm trying to copy is at 12(%ebp)
new_string: 
    pushl   %ebp
    movl    %esp, %ebp
    pushl   %edi
    subl    $20, %esp
    movl    12(%ebp), %ecx
    movl    %ecx, %edi
    movl    (%ecx), %ecx
    movl    %ecx, -8(%ebp)

;get the length of the string + 1, allocate space for it
.STR_ALLOCATE: 
    movl    $0, %eax
    movl    $-1, %ecx
    repnz   scasb
    movl    %ecx, %eax
    notl    %eax
    subl    $1, %eax
    addl    $1, %eax
    movl    %eax, (%esp)
    call    malloc
    movl    %eax, -12(%ebp)

;copy value of of the char* back to %eax, save it to the stack, pass the address back
.STR_DUP: 
    movl    -8(%ebp), %eax
    movl    %eax, -12(%ebp)
    leal    -12(%ebp), %eax

.END:
    popl    %edi
    leave
    ret

Когда я запускаю код, я возвращаю только часть char*. Пример: переход в «Переполнение стека» дает мне «Stac@@#$$». Я предполагаю, что я делаю что-то не так с movl, не совсем уверен, что.

p/s: я почти уверен, что мой strlen работает.

Часть 2. Будет ли код, который я написал, возвращать указатель на вызывающую программу? Как и в возможности освободить любое пространство, которое я выделил позже.


person rlhh    schedule 13.10.2012    source источник
comment
Поскольку вы правильно поняли 4 символа, я подозреваю, что вы копируете область размером с указатель (слово) вместо всей строки, т.е. е. в каком-то месте вы путаете указатель и массив (за исключением того, что здесь это более вредно, чем в C).   -  person    schedule 13.10.2012
comment
Я предполагаю, что ваш прототип выглядит так: mystrcpy(char * src, char** dest) из-за movl (%ecx),%ecx, поскольку это не совсем то же самое, что и strcpy, возможно, вам следует сначала написать код C и добавить это на ваш вопрос   -  person Marco van de Voort    schedule 13.10.2012
comment
Вам не нужно выделять память для strcpy() или strlen(). Вы прекращаете чтение/запись после байта со значением 0.   -  person Alexey Frunze    schedule 13.10.2012
comment
@ H2CO3 да, я почти уверен, что ты прав, но я сам этого не вижу.   -  person rlhh    schedule 13.10.2012
comment
@MarcovandeVoort Я добавил код на C.   -  person rlhh    schedule 13.10.2012
comment
@AlexeyFrunze, даже если мне нужен указатель, указывающий на char*? Думаю, да, если мне нужен указатель.   -  person rlhh    schedule 13.10.2012
comment
Указатель всего 4 байта. У вас нет запасного реестра, чтобы хранить его? Если нет, разве у вас нет стека для его хранения? Конечно, он не переполнится из-за всего лишь 4 дополнительных байтов, не так ли?   -  person Alexey Frunze    schedule 13.10.2012
comment
@AlexeyFrunze Хорошо, я думаю, то, что я делаю, больше похоже на strdup, потому что я уничтожу исходный char *, я не могу просто указать на исходный char *. Мне нужно скопировать значение char*, а затем вернуть указатель на новый char*. Извините за путаницу.   -  person rlhh    schedule 13.10.2012
comment
Я понимаю. Вы должны были уточнить это с самого начала, теперь это более ясно из вашего кода C.   -  person Alexey Frunze    schedule 13.10.2012


Ответы (1)


С немного ржавыми навыками ассемблера это будет выглядеть так:

    pushl   %ebp
    movl    %esp, %ebp
    pushl   %edi
    pushl   %esi
    subl    $20, %esp
    movl    12(%ebp), %edi
;get the length of the string + 1, allocate space for it
.STR_ALLOCATE: 
; next is dangerous. -1 is like scan "forever". You might want to set a proper upper bound here, like in "n" string variants.
    movl    $-1, %ecx
    repnz   scasb
    notl    %ecx
;    subl    $1, %ecx
;    addl    $1, %ecx
    movl    %ecx, -8(%ebp)
    pushl   %ecx
    call    malloc
    add     $4,%esp
    movl    %eax, -12(%ebp)   
    movl    -8(%ebp),%ecx
    movl    %eax, %edi
    movl    12(%ebp).%esi
    rep     movsb
    movl    -12(%ebp),%eax
    popl    %esi
    popl    %edi
    leave
    ret     
person Marco van de Voort    schedule 13.10.2012
comment
Что ж, код работает, но если я попытаюсь освободить исходный char* после освобождения нового char*, я получу сообщение об ошибке, говорящее, что он уже освобожден. - person rlhh; 13.10.2012
comment
И освобождает нормально без вызова рутины? Попробуйте напечатать значения указателя до и после подпрограммы. Я не знаю, какая у вас точная цель и ABI, я просто скопировал стиль оригинала и сохранил все лишние регы. - person Marco van de Voort; 14.10.2012