Обмен двух указателей int в сборке x86

Я хочу поменять местами два указателя int.

Я могу сделать это в C, как это

void swap(int* a, int* b)
    int temp = *a;
    *a = *b;
    *b=temp;

Сейчас я пытаюсь сделать это в сборке, но, и терпите меня, я не понимаю, почему это не работает

push %ebp
mov %esp,%ebp   

mov 8(%ebp), %ecx       #a 
mov 12(%ebp), %ebx      #b

mov (%ecx), %eax        #move o a para temp
mov (%ebx), %ecx        #move o b para o a
mov (%eax), %ebx        #move o temp para o b

mov %ebp, %esp
pop %ebp
ret

Может кто-нибудь объяснить, что я делаю не так?

2 ответа

Решение

Как сказал Weather Vane, код C, который вы показали, не меняет местами два указателя int. Он заменяет два целых числа, на которые указывают два указателя типа int.

Но в вашей сборке вы, кажется, пытаетесь поменять местами два целых числа, на которые указывают два указателя типа int, поэтому ваш код не является полностью потерянным делом.

Изучите это, чтобы понять, что он делает, а затем попробуйте:

mov (%ecx), %eax
mov (%ebx), %edx
mov %edx, (%ecx)
mov %eax, (%ebx)

Ваш C- код пытается поменять значения, на которые указывают указатели, но ваш ассемблерный код, похоже, рассматривает значения как указатели, ведущие к segmentation faults, Одним из способов справиться с этим является использование дополнительных регистров для хранения указателей и значений, на которые они указывают.

32-битный CDECL позволяет нам использовать EAX, ECX и EDX, не беспокоясь о сохранении их значений. Нам понадобится 4-й регистр, и мы должны сохранить его сами.

Я также предполагаю, что вам нужен указатель кадра (подпрограмма может быть написана без него):

push   %ebp
mov    %esp,%ebp
push   %ebx              # Preserve non-volatile EBX register
mov    8(%ebp),%eax      # EAX = Pointer to a (arg1)
mov    12(%ebp),%edx     # EDX = Pointer to b (arg2)
mov    (%eax),%ecx       # Temporarily save value at memory address a (*a) to ECX
mov    (%edx),%ebx       # Temporarily save value at memory address b (*b) to EBX
mov    %ebx,(%eax)       # Move value of b (EBX) to memory address of a (*a)
mov    %ecx,(%edx)       # Move value of a (ECX) to memory address of b (*b)
pop    %ebx              # Restore non-volatile EBX register
pop    %ebp
ret

Теоретически вы можете полностью удалить кадр стека (может усложнить отслеживание стека в отладчике). Код мог использовать ESP для доступа к аргументам, а не EBP:

push   %ebx              # Preserve non-volatile EBX register
mov    8(%esp),%eax      # EAX = Pointer to a
mov    12(%esp),%edx     # EDX = Pointer to b
mov    (%eax),%ecx       # Temporarily save value at memory address a (*a) to ECX
mov    (%edx),%ebx       # Temporarily save value at memory address b (*b) to EBX
mov    %ebx,(%eax)       # Move value of b (EBX) to memory address of a (*a)
mov    %ecx,(%edx)       # Move value of a (ECX) to memory address of b (*b)
pop    %ebx              # Restore non-volatile EBX register
ret

Примечание. Неспособность сохранить (согласно 32-битному соглашению о вызовах CDECL) энергонезависимые регистры, такие как EBX, EBP, ESI и EDI, является ошибкой. В простом тестовом коде это может показаться работающим, но в более сложном коде с оптимизациями вы можете столкнуться с неопределенным поведением, если строго не соблюдается соглашение о вызовах.

Другие вопросы по тегам