Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

how to concatenate strings? Send or get string args #56

Open
zhuxiujia opened this issue Feb 26, 2021 · 2 comments
Open

how to concatenate strings? Send or get string args #56

zhuxiujia opened this issue Feb 26, 2021 · 2 comments

Comments

@zhuxiujia
Copy link

Hello, I am a beginner wasm
how do I concatenate strings? Send string?in this jit-demo

@0xekez
Copy link
Contributor

0xekez commented May 30, 2021

This demo doesn't support that but adding the functionality wouldn't be too bad. In Cranelift you can make foreign calls to libc functions without too much trouble. See here for where I do that in my Cranelift Lisp.

Once you've got foreign calls working you could concatenate two strings the same way you normally would in C with calls to strcat and friends.

@lechatthecat
Copy link

lechatthecat commented Feb 11, 2022

You can define anonymous string like this:

fn create_anonymous_string(&mut self, string_content: &str) -> Value {
    self.data_ctx.define(string_content.as_bytes().to_vec().into_boxed_slice());

    let sym = self
        .module
        .declare_anonymous_data(true, false)
        .expect("problem declaring data object");

    let _result = self.module
         .define_data(sym, &self.data_ctx)
         .map_err(|e| e.to_string());
    
    let local_id = self
        .module
        .declare_data_in_func(sym, &mut self.builder.func);
    self.data_ctx.clear();
    
    let pointer = self.module.target_config().pointer_type();
    self.builder.ins().symbol_value(pointer, local_id)
}

Call this like:

let mut string_content_with_terminator = string_content.to_owned();
string_content_with_terminator.push('\0');
let symbol = self.create_anonymous_string(&string_content_with_terminator);

The string data created by the above function can be concatenated by using C functions as @ezekiiel said.

// anonymous string1
let value1 = self.translate_expr(expr1);
// anonymous string2
let value2 = self.translate_expr(expr2);

let len1 = self.get_str_len(value1);
let len2 = self.get_str_len(value2);
let len_both = self.builder.ins().iadd(len1, len2);
let one = self.builder.ins().iconst(self.int, 1);
let len_both = self.builder.ins().iadd(len_both, one);
let location = self.malloc(len_both);

self.strcpy(location, value1);
self.strcat(location, value2);

Each C function is called like this:

fn get_str_len(&mut self, val: Value) -> Value {
    let mut sig = self.module.make_signature();
    let word = self.module.target_config().pointer_type();
    sig.params.push(AbiParam::new(word));
    sig.returns.push(AbiParam::new(word));

    let callee = self.module
        .declare_function("strlen", cranelift_module::Linkage::Import, &sig)
        .map_err(|e| e.to_string()).unwrap();

    let local_callee = self.module
        .declare_func_in_func(callee, &mut self.builder.func);

    let arg = val;
    let args = vec![arg];

    let call = self.builder.ins().call(local_callee, &args);
    self.builder.inst_results(call)[0]
} 

fn malloc(&mut self, size: Value) -> Value {
    let mut sig = self.module.make_signature();
    let word = self.module.target_config().pointer_type();
    sig.params.push(AbiParam::new(word));
    sig.returns.push(AbiParam::new(word));

    let callee = self.module
        .declare_function("malloc", cranelift_module::Linkage::Import, &sig)
        .map_err(|e| e.to_string()).unwrap();

    let local_callee = self.module
        .declare_func_in_func(callee, &mut self.builder.func);

    let args = vec![size];

    let call = self.builder.ins().call(local_callee, &args);
    self.builder.inst_results(call)[0]
} 

fn strcpy(&mut self, message_buf: Value, message: Value) {
    let mut sig = self.module.make_signature();
    let word = self.module.target_config().pointer_type();
    sig.params.push(AbiParam::new(word));
    sig.params.push(AbiParam::new(word));

    let callee = self.module
        .declare_function("strcpy", cranelift_module::Linkage::Import, &sig)
        .map_err(|e| e.to_string()).unwrap();

    let local_callee = self.module
        .declare_func_in_func(callee, &mut self.builder.func);

    let args = vec![message_buf, message];

    let _call = self.builder.ins().call(local_callee, &args);
} 

fn strcat(&mut self, message_buf: Value, message: Value) {
    let mut sig = self.module.make_signature();
    let word = self.module.target_config().pointer_type();
    sig.params.push(AbiParam::new(word));
    sig.params.push(AbiParam::new(word));

    let callee = self.module
        .declare_function("strcat", cranelift_module::Linkage::Import, &sig)
        .map_err(|e| e.to_string()).unwrap();

    let local_callee = self.module
        .declare_func_in_func(callee, &mut self.builder.func);

    let args = vec![message_buf, message];

    let _call = self.builder.ins().call(local_callee, &args);
} 

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants