Suppose I have a lib xxx.so. So I get all function names and parameters by
following commnad:
readelf -Ws xxx.so |c++filt
It will output following:
711: 00270209 40 FUNC GLOBAL DEFAULT 8 debug_c_tree
7712: 00270231 128 FUNC GLOBAL DEFAULT 8 pp_c_tree_decl_identifier
7713: 00270723 90 FUNC GLOBAL DEFAULT 8 pp_c_init_declarator
7714: 002f546c 0 NOTYPE GLOBAL DEFAULT ABS _edata
7715: 002f546c 0 NOTYPE GLOBAL DEFAULT ABS __bss_start
7716: 002fc9e1 0 NOTYPE GLOBAL DEFAULT ABS _end
But how can I easily dump all function body like following in a elf binary:
debug_c_tree()
{
mov eax, edx;
....
....
}
....
how can I easily dump all function body
objdump -d xxx.so
objdump -D -z ELFfileName
This will disassemble the entire file including all sections and also
space between functions.
Related
When I build my gstreamer project using CMake I use the following CmakeLists.txt:
cmake_minimum_required(VERSION 3.16)
set(CMAKE_CXX_STANDARD 20)
include(FetchContent)
project(someproject)
find_package(PkgConfig REQUIRED)
pkg_check_modules(GST REQUIRED gstreamer-1.0>=1.4
gstreamer-sdp-1.0>=1.4
gstreamer-video-1.0>=1.4
gstreamer-plugins-base-1.0>=1.4
gstreamer-app-1.0>=1.4
gstreamer-gl-1.0>=1.4)
#some other calls to find_package
add_library(someproject "")
#add source directories
target_include_directories(GUI_lib PUBLIC include "${OTHER_FIND_PACKAGE_INCLUDE_DIRS}"
"${GST_INCLUDE_DIRS}")
target_link_libraries(someproject PUBLIC "${OTHER_FIND_PACKAGE_LIBS}" "${GST_LIBRARIES}" -lGL -lepoxy)
This results in the following error:
in function `drawCallback(_GstElement*, unsigned int, unsigned int, unsigned int, void*)':
undefined reference to `gst_gl_filter_get_type'
undefined reference to `gst_gl_filter_draw_fullscreen_quad'
I have searched my gstreamer install and verified that there exists a shared library that defines these symbols using the following snippet (asterisks for emphasis):
% readelf -s --wide /usr/lib/gstreamer-1.0/libgstopengl.so | rg gl_filter
121: 0000000000000000 0 FUNC GLOBAL DEFAULT UND gst_gl_filter_render_to_target_with_shader
* 242: 0000000000000000 0 FUNC GLOBAL DEFAULT UND gst_gl_filter_draw_fullscreen_quad
305: 0000000000000000 0 FUNC GLOBAL DEFAULT UND gst_gl_filter_add_rgba_pad_templates
421: 0000000000000000 0 FUNC GLOBAL DEFAULT UND gst_gl_filter_render_to_target
* 447: 0000000000000000 0 FUNC GLOBAL DEFAULT UND gst_gl_filter_get_type
470: 0000000000000000 0 FUNC GLOBAL DEFAULT UND gst_gl_filter_filter_texture
So, I added the following to my CMake file:
add_library(gstopenglextras SHARED IMPORTED)
set_target_properties(gstopenglextras PROPERTIES
IMPORTED_LOCATION "/usr/lib/gstreamer-1.0/libgstopengl.so")
I also changed the target_link_libraries call to:
target_link_libraries(someproject PUBLIC "${OTHER_FIND_PACKAGE_LIBS}" gstopenglextras "${GST_LIBRARIES}" -lGL -lepoxy)
Now I get the following linker error:
/usr/bin/ld: undefined reference to symbol 'gst_gl_filter_get_type'
/usr/bin/ld: /usr/lib/libgstgl-1.0.so.0: error adding symbols: DSO missing from command line
I've read some stuff on circular dependencies and I've tried adding "${GST_LIBRARIES}" before gstopenglextras. However, this does not change the error.
Any ideas?
target_link_libraries(
someproject
PUBLIC
"${OTHER_FIND_PACKAGE_LIBS}"
gstopenglextras
"${GST_LIBRARIES}"
-lGL
-lepoxy
gstgl-1.0
glib-2.0
gmodule-2.0
)
is the call you need to fix this issue.
2023 update The last person to edit this Q deleted the critically important "LATEST LATEST UPDATE" part that #zentrunix had added near the top. I'm reinstating it.
LATEST LATEST UPDATE
Please see my answer below.
Thanks to everyone who took the time to answer and understand this question.
Original question
Say I have my event-driven TCP communications library in C.
From my Raku application, I can call a function in the C library using NativeCall.
my $server = create-server("127.0.0.1", 4000);
Now, from my callback in C (say onAccept) I want to call out to a Raku function in my application (say on-accept(connection) where connection will be a pointer to a C struct).
So, how can I do that: call my Raku function on-accept from my C function onAccept ?
ps. I tried posting using a simple title "How to call Raku code from C code", but for whatever reason stackoverflow.com wouldn't let me do it. Because of that I concocted this fancy title.
I was creating a 32-bit DLL.
We have to explicitly tell CMake to configure a 64-bit build.
cmake -G "Visual Studio 14 2015 Win64" ..
Anyway, now that the code runs, it's not really what I asked for, because the callback is still in C.
It seems that what I asked for it's not really possible.
I tried to use the approach suggested by Haakon, though I'm afraid I don't understand how it would work.
I'm in Windows, and unfortunately, Raku can't find my dlls, even if I put them in C:\Windows\System32. It finds "msvcrt" (C runtime), but not my dlls.
The dll code (Visual Studio 2015).
#include <stdio.h>
#define EXPORTED __declspec(dllexport)
typedef int (*proto)(const char*);
proto raku_callback;
extern EXPORTED void set_callback(proto);
extern EXPORTED void foo(void);
void set_callback(proto arg)
{
printf("In set_callback()..\n");
raku_callback = arg;
}
void foo(void)
{
printf("In foo()..\n");
int res = raku_callback("hello");
printf("Raku return value: %d\n", res);
}
Cmake code for the
CMAKE_MINIMUM_REQUIRED (VERSION 3.1)
add_library (my_c_dll SHARED my_c_dll.c)
Raku code.
use v6.d;
use NativeCall;
sub set_callback(&callback (Str --> int32))
is native("./my_c_dll"){ * }
sub foo()
is native("./my_c_dll"){ * }
sub callback(Str $str --> Int) {
say "Raku callback.. got string: {$str} from C";
return 32;
}
## sub _getch() returns int32 is native("msvcrt") {*};
## print "-> ";
## say "got ", _getch();
set_callback(&callback);
# foo();
When I run
$ raku test-dll.raku
Cannot locate native library '(null)': error 0xc1
in method setup at D:\tools\raku\share\perl6\core\sources
\947BDAB9F96E0E5FCCB383124F923A6BF6F8D76B (NativeCall) line 298
in block set_callback at D:\tools\raku\share\perl6\core\sources
\947BDAB9F96E0E5FCCB383124F923A6BF6F8D76B (NativeCall) line 594
in block <unit> at test-dll.raku line 21
Raku version.
$ raku -v
This is Rakudo version 2020.05.1 built on MoarVM version 2020.05
implementing Raku 6.d.
Another approach could be to save a callback statically in the C library, for example (libmylib.c):
#include <stdio.h>
static int (*raku_callback)(char *arg);
void set_callback(int (*callback)(char * arg)) {
printf("In set_callback()..\n");
raku_callback = callback;
}
void foo() {
printf("In foo()..\n");
int res = raku_callback("hello");
printf("Raku return value: %d\n", res);
}
Then from Raku:
use v6;
use NativeCall;
sub set_callback(&callback (Str --> int32)) is native('./libmylib.so') { * }
sub foo() is native('./libmylib.so') { * }
sub callback(Str $str --> Int) {
say "Raku callback.. got string: {$str} from C";
return 32;
}
set_callback(&callback);
foo();
Output:
In set_callback()..
In foo()..
Raku callback.. got string: hello from C
Raku return value: 32
Raku is a compiled language; depending on the implementation you've got, it will be compiled to MoarVM, JVM or Javascript. Through compilation, Raku code becomes bytecode in the corresponding virtual machine. So it's never, actually, binary code.
However, Raku code seems to be cleverly organized in a way that an object is actually a pointer to a C endpoint, as proved by Haakon Hagland answer.
WRT to your latest problem, please bear in mind that what you are calling is not a path, but a name that is converted to a navive shared library name and also uses local library path conventions to look for them (it's `PATH' on Windows). So if it's not finding it, add local path to it of simply copy the DLL to one of the searched directories.
First of all, my apologies to #Håkon and #raiph.
Sorry for being so obtuse. :)
Håkon's answer does indeed answer my question, although for whatever reason I have failed to see that until now.
Now the code I played with in order to understand Håkon's solution.
// my_c_dll.c
// be sure to create a 64-bit dll
#include <stdio.h>
#define EXPORTED __declspec(dllexport)
typedef int (*proto)(const char*);
proto raku_function;
extern EXPORTED void install_raku_function(proto);
extern EXPORTED void start_c_processing(void);
void install_raku_function(proto arg)
{
printf("installing raku function\n");
raku_function = arg;
}
void start_c_processing(void)
{
printf("* ----> starting C processing..\n");
for (int i = 0; i < 100; i++)
{
printf("* %d calling raku function\n", i);
int res = raku_function("hello");
printf("* %d raku function returned: %d\n", i, res);
Sleep(1000);
}
}
# test-dll.raku
use v6.d;
use NativeCall;
sub install_raku_function(&raku_function (Str --> int32))
is native("./my_c_dll.dll") { * }
sub start_c_processing()
is native("./my_c_dll.dll") { * }
sub my_raku_function(Str $str --> Int)
{
say "# raku function called from C with parameter [{$str}]";
return 32;
}
install_raku_function &my_raku_function;
start { start_c_processing; }
for ^1000 -> $i
{
say "# $i idling in raku";
sleep 1;
}
$ raku test-dll.raku
installing raku function
# 0 idling in raku
* ----> starting C processing..
* 0 calling raku function
# 0 raku function called from C with parameter [hello]
* 0 raku function returned: 32
# 1 idling in raku
* 1 calling raku function
# 1 raku function called from C with parameter [hello]
* 1 raku function returned: 32
# 2 idling in raku
* 2 calling raku function
# 2 raku function called from C with parameter [hello]
* 2 raku function returned: 32
# 3 idling in raku
* 3 calling raku function
# 3 raku function called from C with parameter [hello]
* 3 raku function returned: 32
# 4 idling in raku
* 4 calling raku function
# 4 raku function called from C with parameter [hello]
* 4 raku function returned: 32
# 5 idling in raku
* 5 calling raku function
# 5 raku function called from C with parameter [hello]
* 5 raku function returned: 32
^CTerminate batch job (Y/N)?
^C
What amazes me is that the Raku signature for my_raku_function maps cleanly to the C signature ... isn't Raku wonderful ? :)
$ raku -v
This is Rakudo version 2019.07.1 built on MoarVM version 2019.07.1
The following was done on Raku REPL. What am I doing wrong here? How do I assign values to CArray[WCHAR]?
I want $lpData[0] to be 0xABCD and $lpData[1] to be 0xEF12.
> use NativeCall;
Nil
> constant WCHAR := uint16;
(uint16)
> my $ValueData = 0xABCDEF12;
2882400018
> my CArray[WCHAR] $lpData;
(CArray[uint16])
> $lpData[ 0 ] = ( $ValueData +& 0xFFFF0000 ) +> 0x10;
Type check failed in assignment to $lpData; expected NativeCall::Types::CArray[uint16] but got Array ($[])
in block <unit> at <unknown file> line 1
> $lpData[ 1 ] = $ValueData +& 0x0000FFFF;
Type check failed in assignment to $lpData; expected NativeCall::Types::CArray[uint16] but got Array ($[])
in block <unit> at <unknown file> line 1
Many thanks,
-T
The problem is stated clearly in the error message: in the way you declare it, it's expecting every item to be a CArray[WCHAR]. Declare it this way, as is indicated in the documentation:
use NativeCall;
constant WCHAR = uint16; # No need to bind here also
my $native-array = CArray[WCHAR].new();
$native-array[0] = 0xABCDEF12 +& 0x0000FFFF;
say $native-array.list; # OUTPUT: «(-4334)»
CArray is not exactly a Positional, but it does have AT-POS defined so you can use square brackets to assign values. The error arises when, you try to assign to an non-initialized Scalar (which contains any) as if it were an array. The minimal change from your program is just initializing to a CArray[WCHAR]:
use NativeCall;
constant WCHAR = uint16; # No need to bind here also
my CArray[WCHAR] $native-array .= new;
$native-array[0] = 0xABCDEF12 +& 0x0000FFFF;
say $native-array.list; # OUTPUT: «(-4334)»
crt_printf, crt_scanf, ExitProcess
Windows 7 with masm32v11r for Environment Path
in .asm file, I'd like to call crt_printf to print (or call ExitProcess to end main procedure). However my code goes with:
.386
.model flat,stdcall
option casemap:none
includelib D:\masm32\lib\msvcrt.lib
printf proto C:dword,:vararg
scanf proto C:dword,:vararg
.DATA
print_int DB "%d",0
print_char DB "%c",0
and my call procedure goes with:
PUSH offset __temp13#_cal#main
PUSH offset print_string
CALL crt_printf
ADD ESP, 8
PUSH _realCock#main
PUSH offset print_int
CALL crt_printf
ADD ESP, 8
PUSH offset __temp14#_cal#main
When I Click the button of build All, messages come with:
Microsoft (R) Macro Assembler Version 6.14.8444
Copyright (C) Microsoft Corp 1981-1997. All rights reserved.
Assembling: D:\masm32\bin\object_code.asm
D:\masm32\bin\object_code.asm(105) : error A2006: undefined symbol : crt_printf
D:\masm32\bin\object_code.asm(109) : error A2006: undefined symbol : crt_printf
D:\masm32\bin\object_code.asm(179) : error A2006: undefined symbol : crt_scanf
D:\masm32\bin\object_code.asm(249) : error A2006: undefined symbol : ExitProcess
Assembly Error
I've struggled with such error for 24 hours, Thx!
crt_printf is a special construct of the MASM32 developers to distiguish it from their macro printf. If you don't include \masm32\macros\macros.asm you don't need this special feature:
.386
.model flat,stdcall
includelib \masm32\lib\msvcrt.lib
includelib \masm32\lib\kernel32.lib
printf proto C :dword, :vararg ; msvcrt
ExitProcess proto STDCALL :DWORD ; kernel32
.DATA
fmt db "%s",10,0
hello db "Hello world!",0
.CODE
main PROC
push OFFSET hello
push OFFSET fmt
call printf
add esp, (2 * 4)
push 0
call ExitProcess
main ENDP
END main
The crt_... aliasses are declared in the msvcrt.inc:
.386
.model flat,stdcall
include \masm32\include\msvcrt.inc
includelib \masm32\lib\msvcrt.lib
includelib \masm32\lib\kernel32.lib
printf proto C :dword, :vararg ; msvcrt
ExitProcess proto STDCALL :DWORD ; kernel32
.DATA
fmt db "%s",10,0
hello db "Hello world!",0
.CODE
main PROC
push OFFSET hello
push OFFSET fmt
call crt_printf
add esp, (2 * 4)
push 0
call ExitProcess
main ENDP
END main
If you want the whole bunch with all declarations and macros then include masm32rt.inc:
include \masm32\include\masm32rt.inc
.DATA
fmt db "%s",10,0
hello db "Hello world!",0
.CODE
main PROC
push OFFSET hello
push OFFSET fmt
call crt_printf
add esp, (2 * 4)
printf ("Hello again: %s\n",OFFSET hello);
push 0
call ExitProcess
main ENDP
END main
The title says it all. When developing a module, how do I force reload, to test new code? I can switch from module to script and introduce binding problems and namespace conflicts, or I can change the version every time I fix a typo. Both are bad options.
What I'm looking for is something like import/force %my-module.reb to reload the module in running session (now I have to restart R3 which is not very fast pattern to use).
I don't know how you're importing your modules, but if you assign the return value of the import function to a variable re-executing the import loads the new code.
For example I have the file mod_a.reb:
REBOL []
forever [
b: import %./mod_b.reb
b/hello
wait 10
]
and the file mod_b.reb:
REBOL []
hello: function [] [
print "Hello"
]
If you run r3 ./mod_a.reb you see the "Hello" string printed every 10 seconds. If you modify the string in mod_b.reb while mod_a.reb is running you see a different string printed.
Currently module does not overwrite existing values (for security reasons).
It works like:
>> m: module [name: test][ export my-func: does[print "hello"]]
>> m/my-func
hello
>> my-func ;<- will error because module was not imported yet
** Script error: my-func has no value
>> import m
>> my-func ;<- now `my-func` is in user's but also `lib` contexts
hello
>> lib/my-func
hello
;-- one must unset it in both contexts
;-- and also remove module from list of existing modules
>> remove/part find system/modules 'test 3 unset 'my-func unset in lib 'my-func
>> import module [name: test][ export my-func: does[print "hello again"]]
>> my-func
hello again
One can simplify it a little bit using private flag and version:
>> import module [name: test version: 1.0.0 options: [private]][export my-func: does[print "hello"]]
>> lib/my-func ;<- will error, because module is private
** Script error: cannot access my-func in path lib/my-func
>> my-func ;<- but it is still in user's context
hello
>> unset 'my-func
>> import module [name: test version: 1.0.1 options: [private]][export my-func: does[print "hello again"]]
>> my-func
hello again
It's also possible to write a function for module unloading (although it may not work in all cases)
unload-module: function[module [word!]][
m: system/modules/:module
unless m [ exit ]
e: select spec-of m 'exports
forall e [
print ["Unsetting:" e/1]
try [unset in system/contexts/user e/1]
try [unset in system/contexts/lib e/1]
]
remove/part find system/modules module 3
m
]
; than:
>> import module [name: test][export my-func: does[print "hello"]]
>> my-func
hello
>> unload-module 'test
Unsetting: my-func
>> import module [name: test][export my-func: does[print "hello again"]]
>> my-func
hello again