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

MIPS ELF imported symbols are not recognized correctly #796

Closed
martonilles opened this issue Sep 17, 2022 · 2 comments
Closed

MIPS ELF imported symbols are not recognized correctly #796

martonilles opened this issue Sep 17, 2022 · 2 comments
Assignees

Comments

@martonilles
Copy link

Describe the bug
I have the following file (same as in #795).

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

const int NUMBER = 42;
const char VERSION[] = "11.22";
const char *VERSION2 = "22.33";


void function1 (const char* str) {
   char buffer[16];
   strcpy(buffer, str);
}

int main(int argc, char *argv[]) {
   printf("Hello %s %s\n", VERSION, VERSION2);

   exit(0);
}

Which is compiled to MIPS platforms:

test-mips-64bit-le: test.c
        mips64el-linux-gnuabi64-gcc-10 -o $@ $^

test-mips-64bit-le-lib: test.c
        mips64el-linux-gnuabi64-gcc-10 -o $@ -shared $^

test-mips-64bit-be: test.c
        mips64-linux-gnuabi64-gcc-10 -o $@ $^

test-mips.zip

Except the shared lib (test-mips-64bit-le-lib), these parse correctly, but selecting imported symbols/function is failing.

To Reproduce
I have the following python code to show list imported symbols/functions:

import lief
import sys

lief.logging.set_level(lief.logging.LOGGING_LEVEL.DEBUG)
l = lief.parse(sys.argv[1])


print("SYMBOLS", [s.name for s in l.symbols])
print("FUNCTIONS", [s.name for s in l.functions])
print("IMPORTED SYMBOLS", [s.name for s in l.imported_symbols])
print("IMPORTED FUNCTIONS", [s.name for s in l.imported_functions])

Running it results in the following:

SYMBOLS ['', '_DYNAMIC_LINKING', 'VERSION', 'VERSION2', '_IO_stdin_used', '__RLD_MAP', 'main', '_ITM_registerTMCloneTable', 'exit', '__gmon_start__', 'strcpy', '__stack_chk_fail', '__stack_chk_guard', 'printf', '_ITM_deregisterTMCloneTable', '__libc_start_main', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'crt1.o', 'hlt', '__abi_tag', 'crtstuff.c', '__CTOR_LIST__', '__DTOR_LIST__', 'deregister_tm_clones', 'register_tm_clones', '__do_global_dtors_aux', 'completed.1', 'dtor_idx.0', 'frame_dummy', 'test.c', 'crtstuff.c', '__CTOR_END__', '__FRAME_END__', '__do_global_ctors_aux', '', '_MIPS_STUBS_', '__DTOR_END__', '_DYNAMIC', '__TMC_END__', '_gp', '__libc_start_main@GLIBC_2.34', '_DYNAMIC_LINKING', '_ITM_deregisterTMCloneTable', 'data_start', 'printf@GLIBC_2.0', 'function1', 'NUMBER', '__stack_chk_guard@GLIBC_2.4', '_edata', 'VERSION', '_fini', '__stack_chk_fail@GLIBC_2.4', 'VERSION2', 'strcpy@GLIBC_2.0', '__data_start', '__gmon_start__', 'exit@GLIBC_2.0', '__dso_handle', '_IO_stdin_used', '_fdata', '__RLD_MAP', '_end', '__bss_start', 'main', '__start', '_ftext', '_GLOBAL_OFFSET_TABLE_', '_fbss', '_ITM_registerTMCloneTable', '_init']
FUNCTIONS ['_init', '__start', 'deregister_tm_clones', 'register_tm_clones', '__do_global_dtors_aux', 'frame_dummy', 'function1', 'main', '__do_global_ctors_aux', '__libc_start_main', 'printf', '__stack_chk_fail', 'strcpy', 'exit', '_fini']
IMPORTED SYMBOLS ['__gmon_start__', '__stack_chk_guard', '__stack_chk_guard@GLIBC_2.4', '__gmon_start__']
IMPORTED FUNCTIONS ['__gmon_start__', '__gmon_start__']

Expected behavior
Neither printf nor strcpy are listed in imported, while they should be.

For each ELF Symbol is_imported status is defined here:

bool Symbol::is_imported() const {
  // An import must not be defined in a section
  bool is_imported = shndx() == static_cast<uint16_t>(SYMBOL_SECTION_INDEX::SHN_UNDEF);

  // An import must not have an address
  is_imported = is_imported && value() == 0;

  // its name must not be empty
  is_imported = is_imported && !name().empty();

  // It must have a GLOBAL or WEAK bind
  is_imported = is_imported && (binding() == SYMBOL_BINDINGS::STB_GLOBAL ||
                                 binding() == SYMBOL_BINDINGS::STB_WEAK);

  // It must be a FUNC or an OBJECT
  is_imported = is_imported && (type() == ELF_SYMBOL_TYPES::STT_FUNC ||
                                 type() == ELF_SYMBOL_TYPES::STT_GNU_IFUNC ||
                                 type() == ELF_SYMBOL_TYPES::STT_OBJECT);
  return is_imported;
}

However on MIPS symbols have value:

   Num:    Value          Size Type    Bind   Vis      Ndx Name
    10: 0000000120000d70     0 FUNC    GLOBAL DEFAULT  UND strcpy@GLIBC_2.0 (3)
    13: 0000000120000d50     0 FUNC    GLOBAL DEFAULT  UND printf@GLIBC_2.0 (3)

While on other platforms (like arm/x86) they do not:

   Num:    Value  Size Type    Bind   Vis      Ndx Name
     3: 00000000     0 FUNC    GLOBAL DEFAULT  UND printf@GLIBC_2.4 (3)
     8: 00000000     0 FUNC    GLOBAL DEFAULT  UND strcpy@GLIBC_2.4 (3)

Getting the value in LIEF for printf using print("PRINTF VALUE", [(s.name, s.value) for s in l.symbols if s.name == 'printf']) also shows this:

On MIPS: PRINTF VALUE [('printf', 4831841616)]
On ARM32: PRINTF VALUE [('printf', 0)]
On X86_64: PRINTF VALUE [('printf', 0)]

Not sure if not having a value is a mandatory requirement for imported functions, radare2 also has a bit different definition:

In _r_bin_elf_get_symbols_imports:

<snip>
				bool is_imported = false;
				if (type == R_BIN_ELF_IMPORT_SYMBOLS) {
					if (sym[k].st_value) {
						toffset = sym[k].st_value;
					} else if ((toffset = get_import_addr (bin, k)) == -1) {
						toffset = 0;
					}
					tsize = 16;
					is_imported = sym[k].st_shndx == STN_UNDEF;
<snip>
@nikaiw
Copy link

nikaiw commented Sep 18, 2022

Glad to see this issue open, I just noticed the same issue for an elf on powerpc and was just starting to investigate it
Likewise, on powerpc symbols have value:

74: 10014c14    84 FUNC    GLOBAL DEFAULT  UND strstr
75: 10014c1c    72 FUNC    GLOBAL DEFAULT  UND setgid
83: 10014c24    76 FUNC    GLOBAL DEFAULT  UND sscanf

running print("PRINTF VALUE", [(s.name, s.value) for s in l.symbols if s.name == 'printf']) also shows this:

PRINTF VALUE [('printf', 268520356)]

Mrbenoit624 pushed a commit to Mrbenoit624/LIEF that referenced this issue Sep 19, 2023
mips and powerpc add a st_value for their import function (issue lief-project#796)
@romainthomas
Copy link
Member

This issue has been resolved!

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

No branches or pull requests

3 participants