Передача указателя на функцию сборки
Я новичок в программировании сборки. Я использую платформу x86 с GCC (Linux).
У меня есть функция, которую я хочу вызвать из C:
myfunc ( unsigned char * s1, unsigned char * s2, int someint );
Функция будет занимать ячейки памяти s1 и s2 и сравнивать их, затем увеличивать и сравнивать и т.д., выполняя некоторую обработку по мере ее использования. Это похоже на memcmp, но я делаю больше.
Мой вопрос: если я передаю указатель на функцию сборки?
И тогда, как я могу сказать "дайте мне значение, сохраненное на этом адресе памяти"?
Вот что я до сих пор:
Чтобы получить первую функцию arg ( "s1" ) из стека, я делаю это (someaddress - 32-разрядное целое число, и я работаю над 32-разрядным процессором):
movl 8(%esp), %ecx
movl %ecx, someaddress
Если я поместил somevar
в %eax
(или %ebx
и т.д.), а затем распечатал его с помощью %p
, я вижу, что его адрес и адрес неподписанного char указателя "s1
" Я прошел, это одно и то же. Но я подозреваю, что то, что я на самом деле сделал, берет адрес памяти, преобразовывает его в целое число и затем помещает это целое число в некоторый адрес.
Например, если я тогда сделаю это:
movl pos1, %eax
movl pos2, %ebx
cmp (%eax),(%ebx)
Я получаю "Ошибка: слишком много ссылок на память для` cmp". Я не совсем уверен, что это значит, кроме "вы испортили"; -)
Итак...
- как передать указатель и сохранить его как указатель?
- как использовать значение указателя в сборке? (например, как
*ptr
в C)
Я хочу посмотреть на операнд LEA?
Я использую Ричарда Блюма "Программирование профессиональной сборки" в качестве моего гида, но Блюм, похоже, не рассматривает этот случай.
Обновление
Большое спасибо за ваш учёный ответ!
К сожалению, я все еще не в состоянии разыгрывать.
Вот упрощенный пример. Функция сборки принимает указатель и должна возвращать его обратно. Вместо этого я получаю:
first_ptr points to 81 (should be 81) <-- from C program
the value is -1543299247 <-- printf called from within assembler
the value is -6028513 <-- printf called from within assembler
my function returned -6028513 <-- return value printed from C program
C Программа:
#include <stdio.h>
#include <string.h>
int main (void) {
unsigned char first;
unsigned char * first_ptr;
first = 'Q';
first_ptr = &first;
printf ("first_ptr points to %i (should be 81)\n",*first_ptr);
printf ("my function returned %i\n", myfunc(first_ptr));
return 0;
}
Программа сборки:
.section .data
msg:
.asciz "the value is %i\n"
.section .bss
.lcomm str, 8
.section .text
.type myfunc, @function
.globl myfunc
myfunc:
# save stack
pushl %ebp
movl %esp, %ebp
# save string arg from stack to "str"
movl 8(%esp), %ecx
movl %ecx, str
# let try printing the ecx dereference
pushl (%ecx)
pushl $msg
call printf
# put the value of str on the stack
# and call printf
pushl (str)
pushl $msg
call printf
# now return the character at pos1
movl (str), %eax
# restore the stack
movl %ebp, %esp
popl %ebp
ret
Ответы
Ответ 1
По крайней мере один из операндов cmp
должен быть регистром. Если вы пытаетесь сравнить содержимое двух мест памяти, вам нужно поместить один из них в регистр. Как получить его в регистр, который вы спрашиваете? Ну, вы сделали это уже с вашим примером кода. Эта строка:
movl 8(%esp), %ecx
Принимает 4 байта в% esp + 8 и помещает их в% ecx. В C-подобном psuedocode:
ecx = *(esp + 8);
Надеюсь, это имеет смысл. Вы можете выполнять аналогичные операции, чтобы вытащить указатели из стека и в регистры, а затем разыменовать их, сравнить разыменованные значения и т.д. Дайте мне знать, если у вас есть еще вопросы!
Изменить - ваши разбитые вопросы:
-
как передать указатель и сохранить его как указатель?
Вы уже это делаете, а ваша команда movl 8(%esp), %ecx
или что-то вроде этого сделает все, что вам нужно.
-
как использовать значение указателя в сборке? (например, как * ptr в C)
Вам нужно снова использовать ()
- загрузить первый байт из указателя в %ecx
из приведенной выше инструкции, например:
movb (%ecx), %edx
В C-подобном псевдокоде, подобном тому, как я использовал его выше, эта инструкция:
edx = *(unsigned char *)ecx;
-
Я хочу посмотреть на операнд LEA?
Вероятно, нет, основываясь на описании вашей проблемы, которую вы предоставили. Это всегда возможно. lea
работает что-то вроде оператора &
в C. В качестве примера эта инструкция:
lea 12(%ecx), %edx
можно перевести в наш псевдокод как:
edx = &(*(ecx + 12))
или более просто:
edx = ecx + 12
Этот пример немного глуп, поскольку мы используем относительно несложный режим адресации, но как насчет чего-то вроде этого:
lea 1(%edx,%ecx,4), %eax
что означает:
eax = &(edx[ecx * 4] + 1)
Часто самым простым решением этих проблем является запись вашей подпрограммы в C, затем ее компиляция и дизассемблирование результатов.
Изменить 2:
Ваша примерная программа кажется почти правильной, но вы пытаетесь разыменовать указатели в памяти - сначала заведите эти указатели в регистры, и вы должны быть в порядке.