| # REQUIRES: webassembly |
| |
| # WebAssembly globals live in an index space of their own and hold values rather |
| # than bytes in the module, so they have no address to be named or read by. Give |
| # them a synthetic address space in which the offset is the global index, and |
| # serve the initializer when there is no process to ask for the current value. |
| |
| # RUN: yaml2obj %s -o %t.wasm |
| # RUN: %lldb %t.wasm \ |
| # RUN: -o "target modules dump sections" \ |
| # RUN: -o "target modules dump symtab" \ |
| # RUN: -o "image lookup -s g_answer" \ |
| # RUN: -o "target modules load --file %t.wasm --slide 0x0000000400000000" \ |
| # RUN: -o "target modules dump sections" \ |
| # RUN: -o "memory read -s 4 -c 1 -f x 0x8000000400000001" \ |
| # RUN: -o "memory read -s 8 -c 1 -f x 0x8000000400000002" \ |
| # RUN: -o "memory read -s 8 -c 1 -f x 0x8000000400000004" \ |
| # RUN: -o "memory read -s 4 -c 1 -f x 0x8000000400000005" \ |
| # RUN: -o "memory read -s 1 -c 1 -f x 0x8000000400000001" \ |
| # RUN: -o exit 2>&1 | FileCheck %s |
| |
| # The global section spans the whole index space, imported globals included, and |
| # has a range of its own so that an index is not also a code or data address. |
| # CHECK: Dumping sections |
| # CHECK: wasm-global {{.*}}[0x8000000000000000-0x8000000000000006) |
| |
| # Each named global becomes a data symbol spanning the one index it occupies. |
| # CHECK: Dumping symbol table |
| # CHECK: Data 0x8000000000000001 0x0000000000000001 {{.*}}g_answer |
| # CHECK: Data 0x8000000000000002 0x0000000000000001 {{.*}}g_double |
| # CHECK: Data 0x8000000000000004 0x0000000000000001 {{.*}}g_wide |
| |
| # A global resolves to its index within that space. |
| # CHECK: 1 symbols match 'g_answer' |
| # CHECK: (wasm-globals.yaml.tmp.wasm.global + 1) |
| |
| # Loading the module keeps the globals in their own space, with the module id. |
| # CHECK: Dumping sections |
| # CHECK: wasm-global {{.*}}[0x8000000400000000-0x8000000400000006) |
| |
| # With no process to ask, a global reads back as the value it is initialized |
| # with, in the byte order WebAssembly gives its memory. |
| # CHECK: 0x8000000400000001: 0x0000002a |
| # CHECK: 0x8000000400000002: 0x3ff8000000000000 |
| # CHECK: 0x8000000400000004: 0x00000000deadbeef |
| |
| # All ones is a value like any other, not the absence of one. |
| # CHECK: 0x8000000400000005: 0xffffffff |
| |
| # A type narrower than the global holding it reads the low bytes, which is how a |
| # char or short global is read. |
| # CHECK: 0x8000000400000001: 0x2a |
| |
| # An imported global is declared by another module, so this one has neither a |
| # value type to size it nor an initializer to read, and gets no symbol. |
| # RUN: %lldb %t.wasm -o "image lookup -s g_imported" -o exit 2>&1 \ |
| # RUN: | FileCheck --check-prefix=NOSYMBOL %s |
| # NOSYMBOL-NOT: symbols match 'g_imported' |
| |
| # A read a global cannot serve fails rather than returning something plausible: |
| # an imported global has no initializer, an initializer that is not a constant |
| # has no value here, and reading past a global would have to come from somewhere |
| # else, because the next index is not adjacent storage. |
| # RUN: %lldb %t.wasm -o "memory read -s 4 -c 1 -f x 0x8000000000000000" -o exit 2>&1 \ |
| # RUN: | FileCheck --check-prefix=NOVALUE %s |
| # RUN: %lldb %t.wasm -o "memory read -s 4 -c 1 -f x 0x8000000000000003" -o exit 2>&1 \ |
| # RUN: | FileCheck --check-prefix=NOVALUE %s |
| # RUN: %lldb %t.wasm -o "memory read -s 8 -c 1 -f x 0x8000000000000001" -o exit 2>&1 \ |
| # RUN: | FileCheck --check-prefix=NOVALUE %s |
| # NOVALUE: error reading data from section global |
| |
| --- !WASM |
| FileHeader: |
| Version: 0x1 |
| Sections: |
| - Type: TYPE |
| Signatures: |
| - Index: 0 |
| ParamTypes: [] |
| ReturnTypes: |
| - I32 |
| - Type: IMPORT |
| Imports: |
| # An imported global occupies index 0, so the module's own globals start at |
| # index 1. It has no initializer here to read back. |
| - Module: env |
| Field: g_imported |
| Kind: GLOBAL |
| GlobalType: I32 |
| GlobalMutable: false |
| # A tag import is what a module built with C++ exceptions carries. Its |
| # descriptor has a shape of its own, which the import section has to know in |
| # order to find where the next import starts. |
| - Module: env |
| Field: __cpp_exception |
| Kind: TAG |
| SigIndex: 0 |
| - Type: FUNCTION |
| FunctionTypes: [ 0 ] |
| - Type: MEMORY |
| Memories: |
| - Minimum: 0x1 |
| - Type: GLOBAL |
| Globals: |
| - Index: 1 |
| Type: I32 |
| Mutable: false |
| InitExpr: |
| Opcode: I32_CONST |
| Value: 42 |
| # The bits of 1.5, a wider constant than the one before it, so the globals |
| # after this one only parse if this one was read at its own width. |
| - Index: 2 |
| Type: F64 |
| Mutable: false |
| InitExpr: |
| Opcode: F64_CONST |
| Value: 0x3FF8000000000000 |
| # Initialized from another global rather than from a constant, so its value |
| # is only known once the module has been instantiated. |
| - Index: 3 |
| Type: I32 |
| Mutable: false |
| InitExpr: |
| Opcode: GLOBAL_GET |
| Index: 0 |
| - Index: 4 |
| Type: I64 |
| Mutable: true |
| InitExpr: |
| Opcode: I64_CONST |
| Value: 3735928559 |
| - Index: 5 |
| Type: I32 |
| Mutable: false |
| InitExpr: |
| Opcode: I32_CONST |
| Value: -1 |
| - Type: CODE |
| Functions: |
| - Index: 0 |
| Locals: [] |
| Body: 412A0F0B |
| - Type: CUSTOM |
| Name: name |
| FunctionNames: |
| - Index: 0 |
| Name: get_42 |
| GlobalNames: |
| - Index: 0 |
| Name: g_imported |
| - Index: 1 |
| Name: g_answer |
| - Index: 2 |
| Name: g_double |
| - Index: 3 |
| Name: g_derived |
| - Index: 4 |
| Name: g_wide |
| - Index: 5 |
| Name: g_all_ones |
| ... |