Официально записываюсь в бегиннерсы по сис кодингу на асме (заболел чето этим). Так что сильно матом не ругайтесь. Прошу помочь вот с чем. Написал я на СИ маленькую прогу да связывания. НУ, прога простая, и решил узнать, как бы это реализовать на асме? Нашел в гугле кое чего и вот что получилось Код (Text): extern dlopen extern dlsym extern dlerror global main section .text main: xchg eax,esp push eax mov byte[edx+ebx],0 push 0x00002 ;ВМЕСТО $101 (так работает) push CALL_TABLE_SYM ; грузим символ из таблицы call dlopen; ну и пытаемся его использовать. jmp cleanup ; в гугле написан вызов cleanup. ; прога дальше ниче не делает, а просто запускается... с segfault:) ret 0 ; не моё cleanup: xor eax,eax ; jz LD_LINK_ERROR ; нафига, если там и так 0? add esp,8 ; тогда это теряет смысл? mov ebx,eax pop eax pop edx xchg eax,esp ret ; НЕ МОЁ:) ; как работает - не знаю. LD_LINK_ERROR: call dlerror ; тут ясно все mov esi,eax ; а вот дальше - объясните плиз. mov edi,ebp stosb lodsb or al,al sub edi,ebp lea eax,[edi-1] mov [ebp],al mov ebx,ebp ret section .data CALL_TABLE_SYM: DB 'showmsg' CALL_MD: DB './dlcurrent' сам я писал примерно такой код (без гугла) Код (Text): push 0x00002 push CALL_TABLE_SYM call dlopen pop eax pop eax ret Тут все ясно, но после загрузки символа из разделяемого объекта дальше ниче не работает. Просвятите пожалуйста а то я уже глаза об монитор сломал.
device ... cleanup: xor eax,eax ; jz LD_LINK_ERROR ; нафига, если там и так 0? ... Там, откуда ты это взял, например, fflinio.asm, написано OR eax,eax. ... call dlerror ; тут ясно все mov esi,eax ; а вот дальше - объясните плиз. mov edi,ebp stosb lodsb or al,al sub edi,ebp lea eax,[edi-1] mov [ebp],al mov ebx,ebp ret ... Функция dlerror вернула указатель на строку, завершающуюся нулем, из _своего_ буфера. Код копирует эту строку _себе_ и добавляет первым байтом ее размер, т.е. делает pascal-like string. Итого перед ret в EBX адрес _своей_ строки. ps по поводу "xchg eax,esp ... mov byte[edx+ebx],0 ... 0x00002 ;ВМЕСТО $101 ... mov edi,ebp" - ты точно представляешь с чем имеешь дело?
А вот такой еще вопрос. Допустим, мы что-то втолкнули в стек, например: push слово call printf Для чего необходимо очищать стек? То есть если после printf не записать что-то типа pop eax, то получим Segmentation Fault. Почему?
device Вроде большой уже а такие вещи спрашиваешь из всех функций wsprintfA требует чтобы прогер сам после нее вычистил стек Код (Text): ; может быть такой вариант push eax push offset format; формат вывода "%04d американских рублей" push offset buffer; куда вывести call _imp__wsprintfA pop eax pop eax pop eax ; очищаем от трех параметров (сама переменная и указатели на формат и буфер) ; а может быть такой push eax push ebx push edi push esi push offset format ; формат вывода "%04d рублей, %04d евро, %04d йен, %04d гривен" push offset buffer; куда вывести call _imp__wsprintfA add esp, 6*4 ;очищаем от шести параметров (четыре переменных и указатели на формат и буфер) ибо сколько он туда загонит параметров он и сам может не знать, а что взять с бедной API?
В общем, сделал так. Откомпилил прогу на си, взял ассемблерный листинг. Стал его ковырять. Доковырял вот до чего: Код (Text): lea ecx, [esp + 4] and esp, -16 push ecx push ebp mov ebp,esp push ecx sub esp, 36 push 2 mov esp, CALL_MD call dlopen mov [ebp-8], eax push CALL_TABLE_SYM mov eax, [ebp - 8] mov [esp], eax call dlsym mov [ebp-12], eax mov [ebp-12], eax call eax mov eax,0 add esp, 36 pop ecx pop ebp lea esp, [ecx - 4] Где-то ошибка, но где?
device взял ассемблерный листинг. Стал его ковырять Смотреть/анализировать или еще менять? Где-то ошибка Покажи "прогу на си".
Код (Text): int main() { void (*sendm)(char *msg); void * module; module = dlopen ("dlcurrent.o", RTLD_NOW); sendm = dlsym(module, "sendm"); sendm("---> FROM ./dlcurrent.o - hi:)"); return 0; }
device Код (Text): ... sub esp, 36 push 2 ;; надо так mov [esp+4],2 mov esp, CALL_MD ;; надо так mov [esp],CALL_MD ... push CALL_TABLE_SYM ;; надо так mov [esp+4],CALL_TABLE_SYM mov eax, [ebp - 8] ;; это лишнее, EAX еще содержит handle ... mov [ebp-12], eax ;; это пусть останется, вдруг захочешь повторно вызвать sendm mov [ebp-12], eax ;; это лишнее call eax ;; тут потерял параметр sendm, надо так ;; mov [esp],тут_адрес_строки_"---> FROM ./dlcurrent.o - hi:)" ;; call eax ... + нет проверки успешного завершения ни dlopen ни dlsym + imho лучше писать так Код (Text): ... typedef void (*sendm_t)(char*); ... sendm_t sendm = (sendm_t) dlsym(module, "sendm"); ... ps компилятор gcc?